I have written a function that reads an array and returns it:
function read_array(f) result (arr)
implicit none
integer, intent(in) :: f
integer, dimension(:), pointer :: arr
integer :: n, i
read(f, *) n
allocate(arr(n))
do i = 1, n
read(f, *) arr(i)
end do
end function read_array
This function is supposed to read an array of integers from a file in unit f and return it as a pointer. The problem is that in the do loop, every read statement reads an entire line, rather than just 1 integer.
Here is how I want my file to look:
5
9 7 4 3 10
And here is how I have to lay it out currently:
5
9
7
4
3
10
So how can I make the read statement not consume an entire line and only read one number?
I think that something like
read(f,*)yourarray
should work for you
Related
After Receiving an integer as input from the keyboard, and passing it to a subroutine that should be responsible for returning the first number, how does one loop through the input and get the first value?
If they enter 123456 , I would need to return 6, then 5, then 3, then 1.in different subroutines.
PROGRAM DATING
IMPLICIT NONE
INTEGER :: num, first, second, fourth, sixth ! varialbe declaration
CHARACTER(Len=10) :: output
WRITE *,' What number did prison Ex give you? '
READ *, num
CALL FIRST( + num)
CALL SECOND( + second)
CALL FOURTH( + fourth)
CALL SIXTH( + sixth)
WRITE(output,'(i2.2)')num ! program output
WRITE *, "Use" ! program output
END PROGRAM DATING
SUBROUTINE FIRST(first)
IMPLICIT NONE
RETURN
END SUBROUTINE FIRST
SUBROUTINE SECOND(Second)
IMPLICIT NONE
RETURN
END SUBROUTINE SECOND
SUBROUTINE FOURTH(fourth)
IMPLICIT NONE
RETURN
END SUBROUTINE FOURTH
SUBROUTINE SIXTH(sixth)
IMPLICIT NONE
RETURN
END SUBROUTINE SIXTH
I have tried to develop subroutines to handle each case but looping through input is tricky
If you want to read six integer digits from a string with six digits, you can read them directly:
integer :: digits(6)
read(*,'(6i1)') digits
You can also convert an existing integer number to a string and do the same:
character(6) :: string
write(string,*) num
read(string,'(6i1)') digits
And you can also compute the digits from the integer using division by 10 and remainders after division:
sixth = mod(num, 10)
num = num/10
fifth = mod(num, 10)
num = num/10
...
Or just make a loop and use the digits array. The above just shows the main idea.
You must make sure that there are indeed six digits or implement some checks.
I am trying to read a text file using a Fortran code. I have a file with 1999 rows and the number of columns vary with each row. Can someone please tell me how one can code such a problem. This is my code for reading a 4*2 text file but I am using do loops which I can't use in my current case.
PROGRAM myread2
IMPLICIT NONE
INTEGER, DIMENSION(100) :: a, b
INTEGER :: row,col,max_rows,max_cols
OPEN(UNIT=11, file='text.txt')
DO row = 1,4
READ(11,*) a(row), b(row)
END DO
PRINT *, a(1)
PRINT *, a(4)
PRINT*, b(4)
END PROGRAM myread2
The best way of reading a file like this depends on how you want to store the data. I'm going to use a ragged array as it's probably simplest, although other container types may be better suited depending on your requirements.
Fortran doesn't have ragged arrays natively, so first you need to define a type to hold each row. This can be done as
type :: RowData
integer, allocatable :: cols(:)
end type
type(RowData), allocatable :: rows(:)
When this container is filled out, the value in the i'th column of the j'th row will be accessed as
value = rows(j)%cols(i)
We can then write a program to read the file, e.g.
type :: RowData
integer, allocatable :: cols(:)
end type
type(RowData), allocatable :: rows(:)
integer :: no_rows
integer :: i
open(unit=11, file='text.txt')
no_rows = count_lines(11)
allocate(rows(no_rows))
do i=1,no_rows
rows(i)%cols = read_row(11)
enddo
Now we just need to write the functions count_lines, which counts the number of lines in the file, and read_row, which reads a line from the file and returns the contents of that line as an array of integers.
Following this question, count_lines can be written as
! Takes a file unit, and returns the number of lines in the file.
! N.B. the file must be at the start of the file.
function count_lines(file_unit) result(output)
integer, intent(in) :: file_unit
integer :: output
integer :: iostat
output = 0
iostat = 0
do while (iostat==0)
read(file_unit, *, iostat=iostat)
if (iostat==0) then
output = output+1
endif
enddo
rewind(file_unit)
end function
Writing read_row, to parse a line of unknown length from a file, can be done by following this question.
This question already has answers here:
Passing character strings of different lengths to functions in Fortran
(2 answers)
Closed 2 years ago.
I have a bunch of files, which contain numbers in rows. I need to write a function, that
reads from file for the first time to find amount of elements in file;
allocates an array and reads numbers from file into array;
returns an array
My function gets a string - name of the file - as an input.
So, the function that I wrote is:
function arrays_proc(name) result(arr)
character(len=128), intent(in) :: name
integer :: i, tmp, ios
character(len=30) :: line
double precision, dimension(:), allocatable :: arr
open(unit=09, file=name, status='old', iostat=ios)
if ( ios /= 0) stop "error opening file"
tmp = 0
do
read(09, '(A)', iostat=ios) line
if (ios /= 0) exit
tmp = tmp + 1
end do
allocate(arr(tmp))
rewind(09)
do i=1, tmp
read(09, '(A)') arr(i)
end do
close(09)
return
end function arrays_proc
Then, in the main program I write
...
real(8), dimension(:), allocatable :: points, potent
points = arrays_proc(trim('carbon_mesh.txt'))
potent = arrays_proc(trim('carbon_pot.txt'))
...
When I run my program, I get instant "error opening file".
I assume the problem is with names of files or how I put them in my function.
Anyway, I hope someone can help me
When compiling your code with a minimal program, GFortran prints the following warnings:
a.f90:4:25:
4 | points = arrays_proc(trim('carbon_mesh.txt'))
| 1
Warning: Character length of actual argument shorter than of dummy argument ‘name’ (15/128) at (1)
a.f90:5:25:
5 | potent = arrays_proc(trim('carbon_pot.txt'))
| 1
Warning: Character length of actual argument shorter than of dummy argument ‘name’ (14/128) at (1)
Trying to print the value of name inside arrays_proc shows that it is filled with garbage. So, guided by the warnings, you can try to change the length of the name parameter to *, which allows a string of any length to be used as input.
With that change, the function manages to open the files.
See also: Passing character strings of different lengths to functions in Fortran
I am having trouble reading exponential from a text file using Fortran.
The entry in the text file looks like the following
0.02547163e+06-0.04601176e+01 0.02500000e+02 0.00000000e+00 0.00000000e+00 3
And the code that I am using looks like the following
read(iunit,'(ES20.8,ES20.8,ES20.8,ES20.8,ES20.8,I2)') dummy1, dummy2, Thermo_DB_Coeffs_LowT(iS,1:3),temp
The error I am getting is
Fortran runtime error: Bad value during floating point read
How can I read these values?
Well here is what I usually do when it is too painful to hand edit the file...
CHARACTER(LEN=256) :: Line
INTEGER, PARAMETER :: Start = 1
INTEGER :: Fin, Trailing_Int, I
DOUBLE, DIMENSION(6) :: Element
...
Ingest_All_Rows: DO WHILE(.TRUE.)
READ(...) Line ! Into a character-string
<if we get to the end of the file, then 'EXIT Ingest_All_Rows'>
Start =1
Single_Row_Ingest: DO I = 1, 6
Fin = SCAN(Line,'eE')+3 !or maybe it is 4?
IF(I ==6) Fin = LEN_TRIM(Line)
READ(Line(Start:Fin),*) Element(I) !fron the string(len-string) to the double.
Line = Line((Fin+1):)
IF(I ==6) Trailing_Int = Element(6)
ENDDO Single_Row_Ingest
<Here we shove the row's 5 elements into some array, and the trailing int somewhere>
ENDDO Ingest_All_Rows
You will have to fill in the blanks, but I find that SCAN and LEN_TRIM can be useful in these cases
I have a program that creates values for the matrix u, and this changes for every iteration f, I want to write out the value of u(2,2) for every iteration f. So for example u(2,2)=5 f=1, u(2,2)=9 f=2, and so on.
Now test(u,n,f) only writes the last value.When it have met my criteria to stop the do loop. I don't want my subroutine to overwrite the file plot.txt every time, I want it to keep u(2,2) for every iterations. I want it to look like this
5 1
9 2
10 3
but not it only writes
15 25
How can this be fixed?
subroutine test(u,n,f)
!input
integer :: n,f,write_unit
real(8) :: u(n+2,n+2)
!lokale
integer :: i,j
real(8) :: vek_x,vek_y
!Skriver vektor verdier til fil som gnuplot skal bruke
open(newunit=write_unit,access='sequential',file='plot.txt',status='unknown')
write(write_unit,*)'# x y vx vy'
vek_x=u(2,2)
!write(write_unit,*) vek_x,f
write(write_unit,*) vek_x,f
write(write_unit,*)''
close(write_unit,status='keep')
"Program" that creates different values for u
do f=1,1000
do j=2,n+1
do i=2,n+1
u(i,j)=(u(i+1,j)+u(i-1,j)+u(i,j+1)+u(i,j-1))/4
!u(i,j)=(1-omega)*u(i,j)+omega*1/4*(u(i+1,j)+u(i-1,j)+u(i,j+1)+u(i,j-1))
end do
end do
if (u(2,2) .eq. 15) then
exit
end if
call test(u,n,f)
end do
Just open the file for appending
open(newunit=write_unit,access='sequential',file='plot.txt',position='append',status='old',action='write')
if that is what you wanted.
For the first time to may want to just create it empty
open(newunit=write_unit,access='sequential',file='plot.txt',status='replace')
close(write_unit)