write in array format in fortran - arrays

I try to write an output file.dat with an nxn matrix format .
I write the code but the output is a column of value f.
Now the problem is: how can i change the output-format of the file to write?
from:
1
2
4
5
...
to: 1,2,3,4 //
5,6,8,.. //
program eccen
implicit none
integer, parameter:: grid=800
integer::i,j,k,n,m
real*8,allocatable::f(:,:)
real*8::xx(grid),yy(grid),mval,Mxval
real*8,allocatable::x(:),y(:)
open(10,file='3d_disk.txt')
n=0
DO
READ(10,*,END=100)
n=n+1
END DO
100 continue
rewind(10)
allocate(x(n),y(n))
do i=1, n
read(10,*) x(i),y(i)
end do
mval=-20.
Mxval=20.
do i=1, grid
xx(i) = mval + ((Mxval - mval)*(i-1))/(grid-1)
yy(i) = mval + ((Mxval - mval)*(i-1))/(grid-1)
end do
open(20,file='3d_map.dat')
allocate(f(n,n))
f=0
do i=1,grid
do j=1,grid
m=0.
do k=1, n
if (x(k) > xx(i) .and. x(k) < xx(i+1) .and. &
& y(k) > yy(j) .and. y(k) < yy(j+1)) then
m=m+1 ! CONTA IL NUMERO DI PARTICELLE
end if
end do
f(i,j)=float(m+1)
I thing that the modification must be here from this:
write(20,*) f(i,j)
end do
write(20,*)
print *,i
end do
end program eccen
to:
do i=1,grid
do j=1,grid
write(20,*) f(i,j)
end do
end do
end do
write(20,*)
print *,i
end do
end program eccen

This statement
write(20,*) f(i,j)
will write the value of f(i,j) then move to the next line, so the file you're getting is exactly what your code is specifying. If you want the file to contain n rows each with n values try
write(20,*) f(i,:)
which ought to make a good stab at writing the whole of row i of the array to a single line in the output file. Of course, this makes your loop over j redundant so you can remove it.

Related

Format columns extracted from different input files in a single output file in Fortran90 [duplicate]

I have a program in Fortran that saves the results to a file. At the moment I open the file using
OPEN (1, FILE = 'Output.TXT')
However, I now want to run a loop, and save the results of each iteration to the files 'Output1.TXT', 'Output2.TXT', 'Output3.TXT', and so on.
Is there an easy way in Fortran to constuct filenames from the loop counter i?
you can write to a unit, but you can also write to a string
program foo
character(len=1024) :: filename
write (filename, "(A5,I2)") "hello", 10
print *, trim(filename)
end program
Please note (this is the second trick I was talking about) that you can also build a format string programmatically.
program foo
character(len=1024) :: filename
character(len=1024) :: format_string
integer :: i
do i=1, 10
if (i < 10) then
format_string = "(A5,I1)"
else
format_string = "(A5,I2)"
endif
write (filename,format_string) "hello", i
print *, trim(filename)
enddo
end program
A much easier solution IMHO ...................
character(len=8) :: fmt ! format descriptor
fmt = '(I5.5)' ! an integer of width 5 with zeros at the left
i1= 59
write (x1,fmt) i1 ! converting integer to string using a 'internal file'
filename='output'//trim(x1)//'.dat'
! ====> filename: output00059.dat
Well here is a simple function which will return the left justified string version of an integer:
character(len=20) function str(k)
! "Convert an integer to string."
integer, intent(in) :: k
write (str, *) k
str = adjustl(str)
end function str
And here is a test code:
program x
integer :: i
do i=1, 100
open(11, file='Output'//trim(str(i))//'.txt')
write (11, *) i
close (11)
end do
end program x
I already showed this elsewhere on SO (How to use a variable in the format specifier statement? , not an exact duplicate IMHO), but I think it is worthwhile to place it here. It is possible to use the techniques from other answers for this question to make a simple function
function itoa(i) result(res)
character(:),allocatable :: res
integer,intent(in) :: i
character(range(i)+2) :: tmp
write(tmp,'(i0)') i
res = trim(tmp)
end function
which you can use after without worrying about trimming and left-adjusting and without writing to a temporary variable:
OPEN(1, FILE = 'Output'//itoa(i)//'.TXT')
It requires Fortran 2003 because of the allocatable string.
For a shorten version.
If all the indices are smaller than 10, then use the following:
do i=0,9
fid=100+i
fname='OUTPUT'//NCHAR(i+48) //'.txt'
open(fid, file=fname)
!....
end do
For a general version:
character(len=5) :: charI
do i = 0,100
fid = 100 + i
write(charI,"(A)"), i
fname ='OUTPUT' // trim(charI) // '.txt'
open(fid, file=fname)
end do
That's all.
I've tried #Alejandro and #user2361779 already but it gives me an unsatisfied result such as file 1.txt or file1 .txt instead of file1.txt. However i find the better solution:
...
integer :: i
character(len=5) :: char_i ! use your maximum expected len
character(len=32) :: filename
write(char_i, '(I5)') i ! convert integer to char
write(filename, '("path/to/file/", A, ".dat")') trim(adjustl(char_i))
...
Explanation:
e.g. set i = 10 and write(char_i, '(I5)') i
char_i gives " 10" ! this is original value of char_i
adjustl(char_i) gives "10 " ! adjust char_i to the left
trim(adjustl(char_i)) gives "10" ! adjust char_i to the left then remove blank space on the right
I think this is a simplest solution that give you a dynamical length filename without any legacy blank spaces from integer to string conversion process.
Try the following:
....
character(len=30) :: filename ! length depends on expected names
integer :: inuit
....
do i=1,n
write(filename,'("output",i0,".txt")') i
open(newunit=iunit,file=filename,...)
....
close(iunit)
enddo
....
Where "..." means other appropriate code for your purpose.
To convert an integer to a string:
integer :: i
character* :: s
if (i.LE.9) then
s=char(48+i)
else if (i.GE.10) then
s=char(48+(i/10))// char(48-10*(i/10)+i)
endif
Here is my subroutine approach to this problem. it transforms an integer in the range 0 : 9999 as a character. For example, the INTEGER 123 is transformed into the character 0123. hope it helps.
P.S. - sorry for the comments; they make sense in Romanian :P
subroutine nume_fisier (i,filename_tot)
implicit none
integer :: i
integer :: integer_zeci,rest_zeci,integer_sute,rest_sute,integer_mii,rest_mii
character(1) :: filename1,filename2,filename3,filename4
character(4) :: filename_tot
! Subrutina ce transforma un INTEGER de la 0 la 9999 in o serie de CARACTERE cu acelasi numar
! pentru a fi folosite in numerotarea si denumirea fisierelor de rezultate.
if(i<=9) then
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+0)
filename4=char(48+i)
elseif(i>=10.and.i<=99) then
integer_zeci=int(i/10)
rest_zeci=mod(i,10)
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=100.and.i<=999) then
integer_sute=int(i/100)
rest_sute=mod(i,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+0)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=1000.and.i<=9999) then
integer_mii=int(i/1000)
rest_mii=mod(i,1000)
integer_sute=int(rest_mii/100)
rest_sute=mod(rest_mii,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+integer_mii)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
endif
filename_tot=''//filename1//''//filename2//''//filename3//''//filename4//''
return
end subroutine nume_fisier

Nested Do and Do while Fortran loops

I'm writing this small program that stores grades in an array and then averages them. The program is supposed to accept up to 10 grades and stop and only accept grades that are > 0 and < 100. Here is my code:
program Average
implicit none
character(len = 50) f_name, l_name
integer i, j, amtOfGrades
real grade, arraySum, avg
Real, Dimension(10)::a
do i = 1, 10
if(.not. (j .LE. 100 .AND. j .GE. 0)) then
write(*,*)'Enter grade: '
read(*,*)a(i)
j = a(i)
arraySum = sum(a)
avg = arraySum/10
else
avg = arraySum/(i-1)
end if
end do
The problem I'm having is with the nested loop section. I cannot get the two conditions I need to work together, which are only up to 10 grades (what the DO is for) AND only accepting grades that in the range of 0-100 (what the DO WHILE is for).
You need to issue an exit statement to quit the loop before the max of 10 grades is entered:
program Console1
use, intrinsic :: iso_fortran_env
implicit none
! Variables
integer, parameter :: maxcount = 10
real :: a(maxcount), ave
integer :: i, count
count = 0
do i = 1, maxcount
write(*,*) 'Enter grade: '
read(*,*) a(i)
if( a(i)<=0.0 .or. a(i)>=100.0) then
exit
end if
count = count + 1
end do
ave = sum(a)/count
write(*,*) 'The average is: ', ave
end program Console1
If you look in help you will see
The EXIT statement causes execution of a DO loop or a named construct to be terminated.
How to do this will depend on what you want to do if an input grade is not 0 <= grade <= 100. Does such an input count towards the limit of 10 grades?
If a bad input does count towards the limit, then you will only need to read from the user 10 times, but you might end up with less than 10 grades total. So you will need to keep track of how many grades have been entered.
Code for this might look like:
program average
implicit none
integer :: i, amtOfGrades
real :: grade, arraySum, avg
real, dimension(10) :: a
amtOfGrades = 0
do i=1,10
write(*,*) 'Enter grade: '
read(*,*) grade
if (0<=grade .and. grade<=100) then
amtOfGrades = amtOfGrades + 1
array(amtOfGrades) = grade
endif
end do
arraySum = sum(a(:amtOfGrades))
avg = arraySum/amtOfGrades
end program
If instead a bad input does not count towards the limit then you will always end up with 10 grades, but you might have to read from the user an infinite number of times.
Code for this might look like:
program average
implicit none
integer :: i
real :: grade, arraySum, avg
real, dimension(10) :: a
do i=1,10
do
write(*,*) 'Enter grade: '
read(*,*) grade
if (0<=grade .and. grade<=100) then
array(i) = grade
exit
endif
enddo
end do
arraySum = sum(a)
avg = arraySum/10
end program

Multiplication of two double-digit integer with arrays in Fortran

I have tried to write a code for multiplying two double-digit integers like ab * cd using arrays and the preliminary multiplying method. However, when I compile my code and insert any input, the output is a wrong result. I traced my code and I got an appropriate result but in compiling is something different. for example i insert 9 9 9 9 which mean 99 * 99 in this code but the result is 1210 instead of 9801.
program main
! multiplication of two double-digit integer ! array method
implicit none
integer , parameter :: size=2
integer , dimension (size)::A
integer , dimension (size)::B
integer , dimension (size+1)::C
integer , dimension (size+2)::D
integer , dimension (size+2)::E
integer :: i=0,carry1=0,carry2=0,carry3=0
do i=1,size,1
read *,A(i)
end do
do i=1,size,1
read *,B(i)
end do
do i= 3,2,-1
C(i)=B(size)*A(i-1)+carry1
if (C(i)>9)then
C(i)=mod (C(i),10)
carry1 = C(i)/10
else
carry1=0
end if
end do
C(1)=carry1
D(4)=0
do i=3,2,-1
D(i)=B(size-1)*A(i-1)+carry2
if (D(i)>9)then
D(i)=mod (D(i),10)
carry2= D(i)/10
else
carry2=0
end if
end do
D(1)=carry2
do i=4,2,-1
E(i)=D(i)+C(i-1)+carry3
if (E(i)>9) then
E(i)=mod (E(i),10)
carry3=1
else
carry3=0
end if
end do
E(1)=D(1)+carry3
do i=4,1,-1
print*,E(i)
end do
end program main

Fortran 90 Reading in Characters and Integers from a data file

Ok, so In my program I'm supposed to take in the name of the data file from the user than open it and read the contents. But when I open and read it all that characters just end up being ****** and all the integers end up being 0. IDK if it's how I'm reading in the file or the format?
The file will contain something like this: (where the number of cities is the first number)
4
SanDiego
0
350
900
1100
Phoenix
350
0
560
604
Denver
900
560
0
389
Dallas
1100
604
389
0
So far my code is this where first I take in the first number than on every firstnumber * I + I pass is supposed to go into the character array city. Now the rest of the numbers I am storing into a integer array, but really want it into a integer matrix called d_table but I couldn't think of a way to do that immediately on the read.
PROGRAM p4
IMPLICIT NONE
INTEGER :: number, status, I, J, K, permutation = 0, distance = 0, distance = 999999
CHARACTER(50) :: filename ! Filenames longer than 50 are truncated
CHARACTER(20), DIMENSION(10) :: city
INTEGER, DIMENSION(100) :: temp
INTEGER, DIMENSION(10,10) :: d_table
INTEGER, DIMENSION(10) :: path, best_path
WRITE (*, '(1x,A)', ADVANCE="NO") "Enter filename: "
READ *, filename
! Open the file we created and read the contents
OPEN(UNIT=15, FILE=filename, STATUS="OLD", ACTION="READ",&
IOSTAT=status)
IF(status /= 0) THEN
PRINT *, "ERROR, could not open file for reading."
STOP
END IF
READ (UNIT=15, FMT = 100, IOSTAT=status) number
J = 0
K = 0
DO I = 0, number*number
IF(I == J*number+J) THEN
READ (UNIT=15, FMT = 200, IOSTAT=status) city(J)
J = J + 1
ELSE
READ (UNIT=15, FMT = 100, IOSTAT=status) temp(K)
K = K + 1
END IF
END DO
K = 0
DO I = 0, number
DO J = 0, number
d_table(I,J) = temp(K)
K = K + 1
END DO
END DO
100 FORMAT(I6)
200 FORMAT (A)
END PROGRAM p4
This line
DO I = 0, number*number
looks wonky to me; the loop will be executed 17 times. Surely you want to read number groups of 5 lines, each group being one city name followed by four integers ? That would be a good case for a little loop nest, something like
do ix = 1, number
read(15,*) city(ix)
do jx = 1, 4
read(15,*) d_table(ix,jx)
end do
end do
Given such a simple input file format there's no need to bother with format statements, list-directed input will work just fine.
I can't see the point of all the index arithmetic the code is doing, perhaps I've missed something.

Fortran subroutines with arrays

I am having an issue with the subroutine in this program, which is at the end of the program. I am getting an error for the division of the arrays in the subroutine, which says "unclassifiable statement." Hope someone can help!
PROGRAM subroutine1
IMPLICIT NONE
INTEGER:: err, ierr, counter, y ,i ,j
!INTEGER, ALLOCATABLE:: gamenum(:)
CHARACTER(30):: fname
REAL, ALLOCATABLE:: AB(:), H(:), TB(:), BA (:), SP(:)
100 Format (A)
200 Format (I2)
300 Format (F9.3)
! 1.Open file
WRITE(*,100)"Please enter a filename:"
READ(*,*) fname
OPEN (UNIT=10, FILE=fname, STATUS="OLD", ACTION="READ", IOSTAT=err)
IF(err.NE.0) STOP "An error occured when opening the file."
! 2.Count Lines
READ(10,*)
counter=0
DO
READ(10,*,IOSTAT=ierr)
IF(ierr .NE. 0) EXIT
counter=counter+1
END DO
!WRITE(*,200) counter
! 3. allocate array
ALLOCATE(AB(counter))
ALLOCATE(H(counter))
ALLOCATE(TB(counter))
ALLOCATE(BA (counter))
ALLOCATE(SP(counter))
! 4. read in data
REWIND(10)
READ(10,*)
DO i=1,counter
READ(10,*) AB(i), H(i), TB(i)
END DO
REWIND(10)
! 5. Call subroutine
CALL arraycalc(counter,AB,H,TB,BA,SP)
! 6. Write out
WRITE(*,100)"Game AB H TB BA SP"
DO i=1,counter
WRITE(*,200,ADVANCE="NO") i
WRITE(*,'(5F9.3)') AB(i), H(i), TB(i), BA(i), SP(i)
END DO
END PROGRAM subroutine1
!HERE IS THE PART WHERE I'M HAVING TROUBLE
SUBROUTINE arraycalc(counter,AB,H,TB,BA,SP)
IMPLICIT NONE
INTEGER, INTENT(IN)::counter
INTEGER::i
REAL,INTENT(INOUT)::AB,H,TB
REAL,INTENT(INOUT):: BA,SP
DO i=1,counter
BA(i)=H(i)/AB(i)
END DO
DO i=1,counter
SP(i)=TB(i)/AB(i)
END DO
END SUBROUTINE
Inside the subroutine, AB, H, TB, BA, and SP are not declared as arrays, so the statement that gives the error indeed makes no sense. They are scalars, so can not be indexed.

Resources