I am working on a piece of legacy F77 code and trying to convert it
to equivalent F90 code. I ran into these lines below and could some
one advise if my conversion is correct?
Fortran 77 code:
Subroutine area(x,y,z,d)
do 15 j=1,10
if (a.gt.b) go to 20
15 CONTINUE
20 Statement 1
Statement 2
Statement 3
end subroutine
I tried to convert it to F90 and came up as below:
Subroutine area(x,y,z,d)
dloop: do j=1,10
if (a>b) then
statement 1
statement 2
statement 3
else
write(*,*) 'Exiting dloop'
exit dloop
end if
end do dloop
end subroutine
Could anyone advise if this methodology is correct? In my results, I am not getting the results that I expect. So there could potentially be a problem with my logic.
You got the translation slightly wrong... The first step is to rebuild the do loop, which loops at 15:
Subroutine area(x,y,z,d)
do j=1,10
if (a.gt.b) go to 20
enddo
20 Statement 1
Statement 2
Statement 3
end subroutine
Now you can see that the goto results in "jumping out of the loop". In this particular example, this equivalent to an exit, and the code can be written as
Subroutine area(x,y,z,d)
do j=1,10
if (a.gt.b) exit
enddo
Statement 1
Statement 2
Statement 3
end subroutine
Related
This question already has answers here:
Error related to EOF command in fortran code
(1 answer)
I am trying to compile following code wrote in fortran but has many errors
(2 answers)
Closed 9 months ago.
My code is causing a compile-time error
Parameter(nx=121,ny=81)
Real u(nx,ny),v(nx,ny),p(nx,ny)
open(1,file='u-component.txt')
Read(1,*)
open(2,file='v-component.txt')
Read(2,*)
open(3,file='Pressure.txt')
Read(3,*)
open(11,file='windVN.TXT')
irec =0
DO while(.not.eof(1))
jj=irec
do 1 j=1,ny
Do 2 i=1,nx
read(1,*) a1,a2,a3,a4,u(i,j)
read(2,*) a1,a2,a3,a4,v(i,j)
read(3,*) a1,a2,a3,p(i,j)
2 continue
1 continue
write(11,*)
write(11,*) '"tstep"', jj, '"item"',1, '"layer"', 0
do 3 j=1,ny
write(11,101) (u(i,j),i=1,nx)
3 continue
write(11,*)
write(11,*) '"tstep"', jj, '"item"',2, '"layer"', 0
do 4 j=1,ny
write(11,101) (v(i,j),i=1,nx)
4 continue
write(11,*)
write(11,*) '"tstep"', jj, '"item"',3, '"layer"', 0
do 5 j=1,ny
write(11,102) (p(i,j)/1000,i=1,nx)
5 continue
irec = irec +1
end do
Write(*,*) irec,' Step', irec*3, ' h'
101 format(121f9.2)
102 format(121f9.2)
Pause
Stop
END
DO while(.not.eof(1))
1
Error: Operand of .not. operator at (1) is REAL(4)
Error: Last command making (build\changeWdata_col.o) returned a bad status
Error: Make execution terminated
How can I fix it?
You should always use IMPLICIT NONE. No exceptions. And really always, when you have some error in your code.
eof() is not a standard Fortran procedure. Some compiler may offer it as an extension, but other compilers do not have to. Fortran have other means using the end= and iostat= specifiers in the I/O statements.
That means, you can use
read(1,*,end=some_label) a1,a2,a3,a4,u(i,j)
or
read(1,*,iostat=some_integer_variable) a1,a2,a3,a4,u(i,j)
The meaning differs, please consult a textbook or tutorial or other StackOverflow questions and answers like How to know that we reached EOF in Fortran 77? or some oriented to a more modern Fortran.
Also, avoid unit numbers below 10, they are often already pre-connected for special purposes. Most often 0,5 and 6, but other numbers could be as well.
This question already has answers here:
Modern Fortran equivalent of an action statement shared by nested DO and GO TO
(1 answer)
Function has no implicit type
(4 answers)
Closed 1 year ago.
I am trying to calculate the moment of inertia in fortran. The formula I am using is following: The code I am using:
program moment
implicit none
real :: cR,h,rho0,a,b,c,d,resultV,pi,resultMI,aMass,exactresMI,exactresV,r,res,z,rho
integer :: m,n
! rho0 = density, cR=capital R( radius),h= height )
rho0=10000
cR=0.05
h=0.1
a=0.d0
b=h
c=0.d0
d=cR
m=1000
n=1000
call cheb2(a,b,m,c,d,n,funV,res)
pi=4*datan(1.d0)
resultV=res*2*pi
exactresV= pi/3*cR**2*h
write(*,*)
write(*,*) "Numerical volume result =", resultV
write(*,*) "Exact volume result = ",exactresV
call cheb2(a,b,m,c,d,n,funV,res)
resultMI=res*2*pi
aMass=exactresV*rho0
exactresMI=3/10.*aMass*cR**2
write(*,*)
write(*,*) "Numerical Moment of Inertia result =", resultMI
write(*,*) "Exact Moment of Inertia result = ",exactresMI
end program
function funV(z,r)
if (r.gt.z*cR/h) then
rho=0.d0
else
rho=1.d0
end if
funV=rho*r
return
end
function funMI(z,r)
if (r.gt.z*cR/h) then
rho=rho0
else
rho=1.d0
endif
funMI=rho*r**3
return
end
include "CHEB.FOR"
Our instructor does not use "implicit none" , so I am really new to this operator. Out instructor gave us CHEB.FOR code for calculating 2 dimensional integrals. I am writing it here:
subroutine ch4xy(al,bl,cl,dl,f,ri)
implicit double precision (a-h,o-z)
common/ttxy/ t1,t2
dimension xx(4),yy(4)
c1=(al+bl)/2.d0
c2=(dl+cl)/2.d0
d1=(-al+bl)/2.d0
d2=(dl-cl)/2.d0
xx(1)=c1+d1*t1
xx(2)=c1+d1*t2
yy(1)=c2+d2*t1
yy(2)=c2+d2*t2
xx(3)=c1-d1*t1
xx(4)=c1-d1*t2
yy(3)=c2-d2*t1
yy(4)=c2-d2*t2
ss=0
do 3 i=1,4
do 3 j=1,4
ss=ss+f(xx(i),yy(j))
3 continue
ri=ss*d1*d2/4.d0
return
end
subroutine cheb2(a,b,m,c,d,n,f,r)
implicit double precision (a-h,o-z)
external f
common/ttxy/ t1,t2
t1=0.187592
t2=0.794654
hx=(b-a)/m
hy=(d-c)/n
rr=0
do 5 i=1,m
do 5 j=1,n
aa=a+(i-1)*hx
bb=aa+hx
cc=c+(j-1)*hy
dd=cc+hy
call ch4xy(aa,bb,cc,dd,f,ri)
rr=rr+ri
5 continue
r=rr
return
end
When I compile the file, a couple of errors and a warning appear:
CHEB.FOR:19:17:
19 | do 3 j=1,4
| 1
Warning: Fortran 2018 deleted feature: Shared DO termination label 3 at (1)
CHEB.FOR:36:11:
36 | do 5 j=1,n
| 1
Warning: Fortran 2018 deleted feature: Shared DO termination label 5 at (1)
momentOFinertia.f95:17:27:
17 | call cheb2(a,b,m,c,d,n,funV,res)
| 1
Error: Symbol 'funv' at (1) has no IMPLICIT type
First, I dont understand why funV is unclassifiable statement, it classifies as a function. Second, our instructor used some old operations which is apparently not valid in new fortran. I dont know what could replace "shared do".
The main problem (fixed by your edit)is that your code misses an end or end program at the end. Alternatively, you could put an end program after your functions and contains between the subroutine and the main program body. That would make the functions to be internal subprograms and would fix your other problem - no implicit type for the functions.
This - putting the functions inside the program as internal subprograms, allows the program to "see" them and then the program can correctly pass them to other procedures. Alternatively, you could make an interface block for them or declare their type and let them be external. See Why do I have to specify implicitly for a double precision return value of a function in Fortran? for more.
You also have a type mismatch. The code you got from your instructor uses double precision but your code uses the default real. You have to synchronize that. Update your code to double precision, either using double precision or using real kinds.
The compiler also warns you that your program is using deleted features. These features were deleted in modern revisions of the Fortran standards. However, the compiler remain largely backwards compatible and will compile the code including those features anyway, unless you request strictly a certain standard revision.
In this case two do-loops use one common continue statement
do 5 ...
do 5 ...
5 continue
This is not allowed and can be fixed by inserting another continue with another label or, better, by using end do.
Here is the source (lets call it test4.F):
do 10 i=1
write(*,*) i
10 continue
end
With gfortran:
$gfortran test4.F
$./a.out
-259911288
with ifort:
$ifort test4.F
$./a.out
0
I know the syntax is incorrect. So both should throw compile-time errors.
Your test program is indeed not valid Fortran, but there isn't a syntax problem.
When the file has a .F suffix both gfortran and ifort assume that the program uses fixed form source. In fixed form source, blanks in statements aren't significant (outside character contexts). Your program is equivalent to:
do10i=1
write(*,*) i
10 continue
end
With comments:
do10i=1 ! Set the real variable do10i to value 1
write(*,*) i ! Write the undefined integer variable i
10 continue ! Do nothing
end ! End execution
Because of implicit typing you have a defaul real variable do10i and so there isn't a syntax error for a do control, and there isn't a do control that sets i to 1.
Instead your program is invalid because you are referencing the value of i although it hasn't first been defined (because it isn't a loop variable). But this isn't an error the compiler has to complain about at compile time (or even run time). A compiler is allowed to print any value it likes. gfortran chose one, ifort another.
Liberal use of implicit none and avoiding fixed-form source are good ways to avoid many programming errors. In this case, use of an end do instead of continue would also alert the compiler to the fact that you intended there to be some looping.
Which version of gfortran are you using? With gfortran-6, the following
PROGRAM MAIN
USE ISO_FORTRAN_ENV, ONLY:
1 COMPILER_VERSION,
2 COMPILER_OPTIONS
C EXPLICIT TYPING ONLY
IMPLICIT NONE
C VARIABLE DECLARATIONS
INTEGER I
DO 10 I = 1
WRITE (*,*) I
10 CONTINUE
PRINT '(/4A/)',
1 'THIS FILE WAS COMPILED USING ', COMPILER_VERSION(),
2 ' USING THE OPTIONS ', COMPILER_OPTIONS()
END PROGRAM MAIN
indeed throws the error
main.F:13:13:
DO 10 I = 1
1
Error: Symbol ‘do10i’ at (1) has no IMPLICIT type
I suspect that test4.F does not include the implicit none statement. Consequently, DO 10 I = 1 is interpreted as an implicitly defined real variable DO10I = 1. Here is a sample of a fixed form statement showing what are now (post Fortran 90) considered significant blanks followed by an equivalent statement without the blanks
DO I=1 , M AX ITER S
DO I = 1 , MAXITERS
Upshot, always use explicit variable declarations in all your programs. Better yet, only write Fortran in free source form main.f90. Free source form is more compatible with modern interactive input devices than fixed form. The maximum line length is 132 characters, compared to the older limit of 72 characters. This reduces the possibility of text exceeding the limit, which could lead the compiler to misinterpret names. Here's the same code in free source form
program main
use ISO_Fortran_env, only: &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
! Explicit typing only
implicit none
! Variable declarations
integer :: i
do i = 1, 3
write (stdout, *) i
end do
print '(/4a/)', &
' This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
and
gfortran-6 -std=f2008ts -o main.exe main.f90
./main.exe
yields
1
2
3
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -std=f2008ts
I am getting my hands wet with Fortran, and am wanting to read a txt file into a an array. I feel like I have tried everything. The txt file is comma seperated 11 rows with 1 number on each row.
Here is my code
program test
real:: obs1,i,jj,count,x_1
real,allocatable:: x(:)
open(1,file='data1.txt',status='old',action='read')
read(1,*) obs1
allocate(x(obs1))
do i=1, obs1
read(1,*) x_1
x(i)=x_1
end do
do jj=1, obs1
print*,x(jj)
end do
end program test
this is the error I am receiving:
The highest data type rank permitted is INTEGER(KIND=8)
This statement
allocate(x(obs1))
contains an error, though I'm not sure it's the one that matches the error message you report. obs1 is a real variable, but array dimensions (and indices) have to be integers. Change the declaration of obs1 to
integer :: obs1
Your compiler ought to complain about using a real variable in the do loop control too, do i=1, obs1. Again, use an integer.
As an aside, since you are new to Fortran, learn to use implicit none in every scope within your programs. SO will provide many questions and answers to explain what it means and why it is important, so will any of your favourite Fortran tutorials.
I have a do while loop in my program, who's condition to continue keeps giving me off-by-one errors and I can't figure out why. It looks like this:
do while (ii .le. nri .and. ed(ii) .le. e1)
! do some stuff...
ii = ii + 1
end do
where ii and nri are scalar integers, e1 is a scalar real, and ed is a real array of length nri. What I expect to happen after the last run is that since ii.le.nri returns .false. the second condition is never tested, and I don't get any off-by-one problems. I've verified with the debugger that ii.le.nri really does return .false. - and yet the program crashes.
To verify my assumption that only one condition is tested, I even wrote a small test program, which I compiled with the same compiler options:
program iftest
implicit none
if (returns_false() .and. returns_true()) then
print *, "in if block"
end if
contains
function returns_true()
implicit none
logical returns_true
print *, "in returns true"
returns_true = .true.
end function
function returns_false()
implicit none
logical returns_false
print *, "in returns false"
returns_false = .false
end function
end program
Running this program outputs, as I expected, only
$ ./iftest
in returns false
and exits. The second test is never run.
Why doesn't this apply to my do while clause?
In contrast to some languages Fortran does not guarantee any particular order of evaluation of compound logical expressions. In the case of your code, at the last go round the while loop the value of ii is set to nri+1. It is legitimate for your compiler to have generated code which tests ed(nri+1)<=e1 and thereby refer to an element outside the bounds of ed. This may well be the cause of your program's crash.
Your expectations are contrary to the Fortran standards prescriptions for the language.
If you haven't already done so, try recompiling your code with array-bounds checking switched on and see what happens.
As to why your test didn't smoke out this issue, well I suspect that all your test really shows is that your compiler generates a different order of execution for different species of condition and that you are not really comparing like-for-like.
Extending the answer High Performance Mark, here is one way to rewrite the loop:
ii_loop: do
if (ii .gt. nri) exit ii_loop
if (ed(ii) .gt. e1) exit ii_loop
! do some stuff
ii = ii + 1
end do ii_loop