An app is causing some I/O errors when trying to open some files. The app is pretty large with dozens of subroutines & modules and skipping one of them doesn't fix the problem because another one will cause a similar one. I took one of the subroutines, added some lines (for extra info), recompiled and rerun it. The results is that the environmental variables seem to be missing or fault. For example, when I try to get the current directory with call get_environment_variable('PWD',pwd) and print out the value of pwd (defined as character(len=128)), I'm getting the error Fortran runtime error: End of record. I also tried with cwd but same result. It seems like something in the code is altering these environmental variables or making them inaccessible, but I cannot put my fingers on what is it or how to pinpoint the original issue.
Memory corruption could cause unintended consequences anywhere in the code. It will be impossible to give a right answer unless you provide a "minimum reproducible example" of your problem.
Regarding your error message though: the compiler is telling you that the character variable you're reading PWD in is too short (could be easily hundreds of characters).
I suggest you first query the LENGTH of that character variable, then use an allocatable string to store it and use STATUS to check that everything went right
integer :: char_length,ierr
character(:), allocatable :: pwd
! Get string length of variable PWD
call get_environment_variable('PWD',length=char_length)
if (char_length<=0) stop 'environment does not contain PWD variable'
! Allocate dynamic string
allocate(character(len=char_length) :: pwd)
! Get its value
call get_environment_variable('PWD',value=pwd,status=ierr)
! Check success
select case (ierr)
case (0); ! all right, do nothing
case (1); stop 'PWD does not exist'
case (2); stop 'this compiler does not support environment variables'
end select
Related
In a program I am improving, I noticed that Fortran does not detect file existing or not. This led to a logic error which has not been fixed. I highly appreciate if you could point out the problems or errors and give me your corrections.
open(unit=nhist,file=history,iostat=ierr)!This setting cannot exit program if file does not exist because ierr is always 0
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
!I used below statement, the program exits even though a file is existing
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
There are two distinct problems here. Let's look at them separately.
First, consider
open(unit=nhist,file=history,iostat=ierr)
The comment suggests that ierr is always set to zero. Well, why shouldn't it be set to zero? ierr should be non-zero in the case the case of an error, but is the file not existing an error?
Not necessarily. In the absence of a status= specifier the default status='unknown' is taken. The compiler doesn't have to (and is unlikely to) treat opening in this case as an error if the file doesn't exist. It's likely to create it as needed on a write, or complain when trying to read.
Adding status='old' to the open statement is the usual way of saying "the file should exist".
Second, consider
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
...
If there's an error here, execution is transferred to the statement labelled 700. From this statement ierr is set to a non-zero value and off we go to the if construct to handle that error.
It's just that the statement labelled 700 also happens to be executed even without an error: it's simply the next statement after the open and there's no branch to miss it. [I could give an example of such branching, but I don't want to encourage use of err= in modern code. With the working iostat= things are far preferable.]
But if you just wish to test the existence of a file, consider inquire-by-file:
logical itexists
inquire (file=history, exist=itexists)
if (.not.itexists) error stop "No file :("
Some would argue this is even better than having status='old' in an open statement.
In a program I am improving, I noticed that Fortran does not detect file existing or not. This led to a logic error which has not been fixed. I highly appreciate if you could point out the problems or errors and give me your corrections.
open(unit=nhist,file=history,iostat=ierr)!This setting cannot exit program if file does not exist because ierr is always 0
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
!I used below statement, the program exits even though a file is existing
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
There are two distinct problems here. Let's look at them separately.
First, consider
open(unit=nhist,file=history,iostat=ierr)
The comment suggests that ierr is always set to zero. Well, why shouldn't it be set to zero? ierr should be non-zero in the case the case of an error, but is the file not existing an error?
Not necessarily. In the absence of a status= specifier the default status='unknown' is taken. The compiler doesn't have to (and is unlikely to) treat opening in this case as an error if the file doesn't exist. It's likely to create it as needed on a write, or complain when trying to read.
Adding status='old' to the open statement is the usual way of saying "the file should exist".
Second, consider
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
...
If there's an error here, execution is transferred to the statement labelled 700. From this statement ierr is set to a non-zero value and off we go to the if construct to handle that error.
It's just that the statement labelled 700 also happens to be executed even without an error: it's simply the next statement after the open and there's no branch to miss it. [I could give an example of such branching, but I don't want to encourage use of err= in modern code. With the working iostat= things are far preferable.]
But if you just wish to test the existence of a file, consider inquire-by-file:
logical itexists
inquire (file=history, exist=itexists)
if (.not.itexists) error stop "No file :("
Some would argue this is even better than having status='old' in an open statement.
I am writing a subroutine and main function to call it, but getting error as undefined reference to ___. I found one reason: When I save the main and subroutine in the same file, compile and run that file, everything runs perfectly. However, when I save them into different .f90 files and try to run the main file, I get error. Is there any way I can make subroutine into a separate file and call into main calling program?
I got confused with another place - in the main program at !------ERROR------ place. I referred to Automatic width integer descriptor in fortran 90 I can use I0 as automatic width display indicator. But when I used the same, there is run time error expected integer but got character. Any idea about this?
! saved as sub_program.f90 file
SUBROUTINE sub_program (v1,v2,ctr)
IMPLICIT NONE
INTEGER, INTENT(IN) :: ctr
INTEGER, INTENT (OUT) :: v1,v2
SELECT CASE (ctr)
CASE (1)
v1=1
v2=0
CASE (2)
v1=0
v2=1
END SELECT
RETURN
END SUBROUTINE
! main calling program, saved as caller.f90
PROGRAM caller
IMPLICIT NONE
INTEGER :: v1,v2,ctr
DO ctr = 1,2,1
CALL sub_program (v1,v2,ctr)
WRITE (*,100) 'STEP = ',ctr,'V1 = ',v1,'V2 = ',v2 !------ERROR------
100 FORMAT (I0)
END DO
END PROGRAM
Thanks!
What is your compile command? For me, this compiles and runs normally
gfortran caller.f90 foo.f90 && ./a.out
I0 is an integer indicator, but some items following your WRITE statement are character strings. You can try, for example,
100 FORMAT (3(A, I0, 1X))
where 1X refers to a space.
As a note, if formatting is not terribly important and you're only interested in seeing some quick results, you can use the free format output (WRITE(*,*) ...).
EDIT: I had incorrectly referred to FORMAT as obsolete.
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.
I wrote a subroutine for a Fortran program and I want to execute a command (delete file in the program directory and open a new one) the first, and only first time, the subroutine is called. I know that I can achieve this by creating some flag outside of the subroutine, in the main program, that I set to false at program startup and then set to true upon entering the subroutine. Then I could use this flag in an if statement to figure if the commands I want to execute on the initial call should be executed or not. But this requires me modifying the existing program and I didn't want to do that if I could avoid it. Is there some other way to do what I want to do?
An example might be:
subroutine test(a)
implicit none
integer, intent(inout) :: a
logical, save :: first_time=.true.
if(first_time) then
first_time=.false.
a = a + 12345
else
a = a - 67890
end if
end subroutine test
How about using some characteristic of the output file to determine whether or not to delete it? Time stamp, file lock, a particular file extension, etc.