I am new to doing fortran programing. I would like to open multiple .txt files (CrossSec01 to CrossSec10) and read data an Allocatable arrays into a single file.
My code gives me "end of file error" in the "read". Can any novices out there help me, please?
Here's my code:
implicit none
real(8), allocatable :: dat(:,:,:) ! a 3D array, no defined size yet
integer :: i,j,k,m,n
integer :: x,y,z
open(unit=123,file="crossSec01.txt") ! opens 1st file reads & closes file
!read (100,20) ((dat(i,j,k)
read(123,*) y,x
z=30
close(123)
allocate (dat(i,j,k))
do k=1,z
write(str,'("crossSec",i2.2,".txt")')k
open(unit=345,file=str,status="old")
read(345,*)
read(345,*)
read(345,*)
do i = 1,y
read(345,*)(dat(i,j,k),j=1,x) ! This is where I get my fortran runtime error "end of file" error.
end do
close(345)
end do
allocate (dat(i,j,k))
I think this is where the error occurs. You are allocating the array datwith dimensions i,j,k but i,j,k are not initialised yet. At this moment i,j and k have value as zero. This will make the array dat of zero dimensions and you can't write anything into it. I think you were trying to do allocate (dat(y,x,z)).
Related
I have created a code that reads in a data file and print out the 20 lines of it. I want to develop this by making the code read all the lines within the data file, and only printing out certain lines that comply with an if statement. There are 4 values per data row, and I want it to look at the 3rd value and see if this changes, and if it does then to print that row of values. Can anyone help?
program datafile
implicit none
real*8 um,nm,pN,s
integer*8 au
integer*8 i
real, dimension(1:4)
real, dimension(4) :: file
WRITE(*,*)"test"
OPEN(UNIT=1, FILE="file.dat",STATUS="old",ACTION="read")
WRITE(*,*)"file opened"
do i=1,20
read(1,*) file
write(*,*)file
enddo
close(unit=1)
end program datafile
~
I have an existing Fortran 77 program where the input values are read from an input file.
read (unit=*, fmt=*) value
The read statement automatically jumps to the next line in the file every time it is called.
Is it possible to replace the "reference" index with another data container, like an array?
For example:
read (myarray, fmt=*) value
I tried it but it always reads the first array-element and does not jump automatically to the next element.
I would have to change every read(unit=*, ...) to read(array(i), ...) and increase the i separately to get to the next element.
Since the program is huge, I am looking for a way to keep the existing read statements and just change the source of the data.
So the unit wouldn't be a integer value but a array where every element is a line from my input file.
Does anybody have an idea?
I tried to discribe the problem in code:
(the input_file.input ist just 15 lines with the numbers 1 to 15)
program FortranInput
implicit none
! Variables
integer :: i, inpid
character*130, dimension(100) :: inp_values
character*130 :: value
inpid = 20
! Open File
open(inpid, file='input_file.input')
! Read from file ------------------------------------------------
do i = 1, 15
! read always takes the next line in the file
read(inpid,'(a130)') value
! write each line to new array-element
inp_values(i) = value
! output each line from file to screen
write(*,*) value
end do
close (inpid)
! Read from array -----------------------------------------------
do i = 1, 15
! read always takes the first line in the array
read(inp_values,'(a130)') value
write(*,*) value
end do
end program FortranInput
Yes, in your example you have to always read from the appropriate array element using the (i) syntax. I can't see another way.
However, often you can use a character array as file in multiple records without using the element index. Consider this:
integer :: i, n=15
character*130, dimension(100) :: inp_values
character*130 :: value
integer :: values(100)
do i = 1, n
write(value,*) i
inp_values(i) = value
end do
read(inp_values,'(*(i130,/))') values(1:n)
write(*,*) values(1:n)
or even
read(inp_values,*) values(1:n)
It is important to remember that an internal file does not keep track of the position at which it is opened. The position is only valid within each write or read statement.
Internal files, unlike external files, have no concept of persistent position (between input/output statements). In this regard if you want one read statement to transfer from one record and the next read from another record you will have to reference these records directly.
However, you don't show how you really want to use the input. If you can re-write the input to use a single read statement then the appropriate records will be the source.
For example, if you can rewrite
do i=1,5
read(unit, '(I5)') x(i)
end do
as
read(unit, '(I5,/)') x(1:5)
then you can easily switch to using an internal file.
rogram readfromfile
implicit none
integer :: N, i
integer, dimension(130,2) :: cs
OPEN (UNIT=20,FILE='readtry.txt',STATUS='OLD',FORM='UNFORMATTED',)
do i=1,130
read (*,*) cs(i,1), cs(i,2)
enddo
do i=1,130
print *, cs(i,1), cs(i,2)
enddo
I am a beginner in programming, I just want read data from a file which has two columns and approximately 130 lines. I have tried to write down this code but its not working can someone please help?
The following error appears
gfortran -Wall -c "Rwarray.f95" (in directory: D:\Fortrandir\2Darrays)
Rwarray.f95:7:67:
OPEN (UNIT=20,FILE='readtry.txt',STATUS='OLD',FORM='UNFORMATTED',)
1
Error: Syntax error in OPEN statement at (1)
Compilation failed.
you have a compile time error, not a problem reading. But here's the gist of it:
It complains about a syntax error. Your statement is like this:
open(xxx, xxx, xxx, xxx,)
In order for it to compile, you need to remove the last comma. But I don't think that will give you what you want.
When you open the file, you declare it to be unformatted. Unformatted basically means that it contains the values in some form of binary. What's more, unformatted is not guaranteed to work between computers. So unless this file was written on your system, by a Fortran Program, with the FORM="UNFORMATTED" parameter, I don't think you'll get what you want.
I suspect that your input file looks something like this:
1 3
2 10
31 4711
That would be FORMATTED, not UNFORMATTED.
Then you use read(*, *). But the first * in there refers to "standard input", if you want to read from the file, you want to use the read(20, *), as 20 is the unit on which you opened the input file.
For the write statement, the * is correct, assuming that you want to write to "standard output" -- i.e. the screen.
What I'd further recommend is to use the error handling routines. Add these two variables to your declaration block:
integer :: ios
character(len=100) :: iomsg
And then use them whenever you open, read, or write:
open(unit=xx, file=xxx, status=xxx, action=xxx, form=xxx, io_stat=ios, iomsg=iomsg)
call check(ios, iomsg, "OPEN")
read(20, *, io_stat=ios, iomsg=iomsg) cs(1, i), cs(2, i)
call check(ios, iomsg, "READ")
You'd have to include the check subroutine, of course:
program readfromfile
implicit none
<declaraction block>
<execution block>
contains
subroutine check(ios, iomsg, action)
integer, intent(in) :: ios
character(len=*), intent(in) :: iomsg
character(len=*), intent(in), optional :: action
if (ios == 0) return ! No error occured, return
print*, "Error found. Error code:", ios
print*, "Message: ", trim(iomsg)
if (present(action)) print*, "Action was: ", trim(action)
stop 1
end subroutine check
end program readfromfile
I have a dataset of parameter values for 30 species, and I want to run a script that conducts a simulation for each species. The parameter values are currently stored in a .txt file, where each row is a different species, and each column is a different parameter value. What I'd like to do is set up a do-loop that reads in the relevant row of parameter values for each species, runs the simulation script, and writes a .txt file of the output for each species. Unfortunately, I'm new to fortran and having a lot of trouble understanding how to read in consecutive rows from a .txt file in each step of a do loop. I tried making a simplified script to test whether the read step was working:
PROGRAM DRIVER
IMPLICIT NONE
INTEGER :: mm ! I forgot this line in the first version of this question
and edited to add it in
CHARACTER(7) :: species !! the first column is the species name
REAL*8 :: leaf_variable ! The next 3 columns are variable values
REAL*8 :: stem_variable !
REAL*8 :: root_variable !
OPEN (12, file = "species_parameters.txt") ! open the .txt file
DO mm = 1,30 ! set up the do loop
READ (12,*) species, leaf_variable, stem_variable, root_variable
! Read in the species-specific parameter values
WRITE (*,*) species, leaf_variable, stem_variable, root_variable
! Print the values on the screen just to show the do loop runs
ENDDO
END PROGRAM DRIVER
But when I go to compile, I get the error:
At line XX of file XX (unit = 12, file = 'species_parameters.txt')
Fortran runtime error: End of file
What am I misunderstanding about opening and reading in this file?
Thanks very much for any help.
EDIT: I think I've narrowed down my problem. My understanding is that read() takes in one row in a .txt file at a time, so that in this example:
read(7, *) species, leaf_variable, stem_variable, root_variable
read(7, *) species, leaf_variable, stem_variable, root_variable
The variables should equal the values in the second row of the .txt file. Instead, no matter how many times I put in the read() function, the variable values equal the first row. And, even though there are only 4 columns, I can define as many variables as I want with a read() function:
read(7, *) species, leaf_variable, stem_variable, root_variable,
fake_variable1, fake_variable2, fake_variable3, fake_variable4
where the fake_variable values equal the values in the second row of the .txt file. Am I confused about what read() does, or is there something I need to do to keep my script from reading my entire .txt file as one line?
EDIT #2: The do loop reads line by line correctly now that I've saved my .txt file with Unix encoding using TextWrangler. The original file was saved as a .txt file with Excel. This seems to have solved it, but if anyone has suggestions for a better way to specify the input file format, I'd appreciate it. The first few lines of the input file look like this:
species1,1.2,6.54,10.9
species2,1.42,3.5,8.23
species3,0.85,2.41,4.9
A run time error is when you have an executable, execute it, and it crashes. A compile time error is when the compiler fails to produce an executable.
This code shouldn't compile, because you have IMPLICIT NONE, but haven't declared the integer mm.
What I'd recommend is to get more information:
program driver
use iso_fortran_env
implicit none
character(len=7) :: species
real(kind=real64) :: leaf_variable, stem_variable, root_variable
integer :: u, ioerr
character(len=120) :: iomsg
open(newunit=u, file='species_parameters.txt', action='read', status='old', iostat=ioerr, iomsg=iomsg)
if (ioerr /= 0) then
print *, "Error opening file"
print *, trim(iomsg)
stop 1
end if
do
read(u, *, iostat=ioerr, iomsg=iomsg) species, leaf_variable, stem_variable, root_variable
if (ioerr /= 0) exit ! exits the loop
write(*, *) species, leaf_variable, stem_variable, root_variable
end do
print *, trim(iomsg)
close(u)
end program driver
This will always print the "read past end of file" error, but this is just to check how to program reads anyway.
This should compile, and when you run it, it should give you some information on what is going wrong.
I'm sorry if this has been asked before, but I couldn't find an answer that seemed to work for me. I'm working with an old program, but have made a few modifications to it.
I can include the whole 2500 line program, but it seems like that is a lot.
I've successfully compiled the a program, but it fails when I try and run it. I'm getting a "Fortran runtime error: End of file" at the line which reads the .dat file. I've tried to compile a test segment, using the same .dat file and same variables. It results in the same problem.
PROGRAM OPEN
INTEGER (KIND=1), PARAMETER :: dy=3 ! number of income states
INTEGER (KIND=2) :: OpenStatus
REAL, DIMENSION(dy) :: grid,wt
OPEN(1,file='cygdrive/user/mk.dat',status='old',form='formatted',IOSTAT=OpenStatus)
READ (1,*) grid, wt
IF(OpenStatus>0) STOP 'cannot open mk.dat'
CLOSE(1)
PRINT*, grid(1)
END PROGRAM
The data file referenced is:
-1.7320508e+000
0.0000000e+000
1.7320508e+000
4.1777138e-001
1.6710855e+000
4.1777138e-001
Where each of these numbers is on its own line and preceeded by a space
This generates the same end of file runtime error. I'd really appreciate any help here.
I should add that I compiled with gfortran.
EDIT:
As per High Performance Mark's suggestion below, I've modified it to include an inquire test.
PROGRAM TEST
CHARACTER :: fnm, seq, fort
Logical :: lex
INTEGER (KIND=1), PARAMETER :: dy=3 ! number of income states
INTEGER (KIND=2) :: j,j0,j1,j2,j4,j5,j6,j7,k,jjj,jj,dyy,OpenStatus
REAL, DIMENSION(dy) :: grid,wt
OPEN(1,file='cygdrive/user/mk.dat',status='old',form='formatted',IOSTAT=OpenStatus)
INQUIRE (1, EXIST=lex, NAME=fnm, SEQUENTIAL=seq, FORMATTED=fort)
PRINT*, 'Exists=',lex, ' Name=',fnm, ' Sequential=', seq, 'Formatted=', fort
READ (1,*) grid, wt
IF(OpenStatus>0) STOP 'cannot open mk.dat'
CLOSE(1)
PRINT*, grid(1)
END PROGRAM
The results of the inquire statement are:
Exists= T Name= Sequential=U Formatted=U
My understanding is that the File is found (i.e. exists is returned as true), is un-named and the format and sequential access are returned as unknown (as is direct which I included later). I've also checked the delimiter and padding which are coming back as unknown.
My beginner intuition is telling me that I should try and create a new data file by writing to it with a fortran program and that should solve the problem? Is that correct? If so is there a fundamental misunderstanding at play here i.e. is this a problem with data files from other sources?
Thanks for all your patience.
(Answered in the comments. See Question with no answers, but issue solved in the comments (or extended in chat) )
The OP wrote:
I've fixed this problem-the program was looking for it in a different place, I've now corrected that.