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 would like to have an associate that points to an array (or parts thereof) and is not one indexed.
The following program illustrates the problem:
program test_associate
implicit none(type, external)
integer, parameter :: N = 10
integer :: i, A(0 : N - 1)
A = [(i, i = lbound(A, 1), ubound(A, 1))]
write(*, *) A(0), A(9)
associate(B => A(0 : N - 1))
write(*, *) B(9) ! This writes 8 but should write 9
end associate
end program
I tried
associate(B(0 : N - 1) => A(0 : N - 1))
write(*, *) B(9)
end associate
but this is invalid syntax. (at least in my compiler which is gfortran 9.3)
The syntax
associate (B(0:N-1) => ...)
end associate
is not valid in Fortran: the left-hand side of the association item must be a name. With just a name (which here would be B) it isn't possible to specify properties such as bounds.
The bounds of the associating entity array (again, here B), are given by the results of using LBOUND on the right-hand side (the selector) (Fortran 2018, 11.1.3.3 p.1):
The lower bound of each dimension is the result of the intrinsic function LBOUND (16.9.109) applied to the corresponding dimension of selector
The referenced description of LBOUND explains how the bound is calculated in this case.
Because A(0:N-1) is not a whole array, LBOUND returns 1, and so the lower bound of B in this case is itself 1.
It is possible to have the lower bound of B be something other than 1: have the selector being a whole array. In
associate(B => A)
end associate
B will have lower bound that of A.
In conclusion: it's possible for an associate entity to have lower bound other than 1, but only when the thing it's associated with is a whole array. In particular, in associating with part of an array (and that can include all of the array, such as B => A(:), A(:) not being a whole array) the associating entity always has lower bounds 1.
As Vladimir F says in another answer, a pointer can have bounds controlled as part of pointer assignment.
I do not think that is possible. A(0 : N - 1) is a subarray, it is an expression, no longer the original array. The lower bound of A(0 : N - 1) is 1, not 0.
You can try
dimension A(0:9)
print *,lbound(A(0:8))
end
It will print 1.
Be aware, that your associate may case the array section to be copied and stored in a temporary array.
If you associate to => B, A will correctly write 9.
You can use pointers to point to such sections
program test_associate
implicit none(type, external)
integer, parameter :: N = 10
integer, target :: A(0 : N - 1)
integer, pointer :: B(:)
integer :: i
A = [(i, i = lbound(A, 1), ubound(A, 1))]
write(*, *) A(0), A(9)
B(0:N-1) => A(0:N-1)
write(*, *) B(9) ! This writes 9
end program
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 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 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 )