How to use Fortran 77 subroutines in Fortran 90/95? - fortran

I'm writing a code with Fortran 90 and now I need to use the special functions in the*amos Fotran 77 library(http://www.netlib.org/amos/). Now I found a module interface for those routines(https://github.com/certik/fortran-utils/blob/master/src/amos.f90).
My question is: how can I combine them and use them in my Fortran 90 program and how to compile them correctly?
I have been struggling for this for one whole day and still could not figure it out.
The following is my test code:
PROGRAM TEST_ZBESI
USE set_precisions
USE amos
IMPLICIT NONE
INTEGER :: n, i, nz, ierr
!double precision :: zr,zi, cyr(5), cyi(5)
REAL(kind=DBL) :: zr, zi, cyr(5), cyi(5)
n=5
zr=1.0_DBL
zi=2.0_DBL
call ZBESI(zr,zi,0.0_DBL,1,n,cyr,cyi,nz,ierr)
print *,' '
do i=1, n
write(*,10) i-1, cyr(i)
write(*,11) i-1, cyi(i)
end do
print *,' NZ=', NZ
print *,' Error code:', ierr
print *,' '
10 format(' zr(',I1,') = ',F10.6)
11 format(' zi(',I1,') = ',F10.6)
END PROGRAM TEST_ZBESI
The result I got is the following:
zr(0) = 0.000000
zi(0) = 0.000000
zr(1) = 0.000000
zi(1) = 0.000000
zr(2) = 0.000000
zi(2) = 0.000000
zr(3) = 0.000000
zi(3) = 0.000000
zr(4) = 0.000000
zi(4) = 0.000000
NZ= 0
Error code: 4
It seems I could not get the correct answer no matter how.
I tried to convert the ZBESI.f Fortran 77 code to Fortran 90 code by hand. But the code is so long and it was a disaster.

With extremely few exceptions, FORTRAN 77 is a subset of Fortran 90/95/2003/2008. And in practice, compilers still support the obsolete features. Compiling the FORTRAN 77 and Fortran 90/59/2003/2008 source with the same compiler should produce compatible object modules. You will likely have to compile the two language versions separately since different compiler options will probably be necessary, e.g., for fixed and free-form source layout. With the interfaces in your Fortan 90/95/2003/2008 code, the compiler will use compatible calling conventions.
What specific problems are you having? Do you need to know the compiler options for FORTRAN 77? What compiler are you using?
EDIT: You have to compile the module before the source code that uses it. It is convenient to compile the FORTRAN 77 first, into an object file, and then use the fortran command that compiles the Fortran 95 to link everything. So try:
ifort -c -fixed ZBESI.f
ifort ZBESI.o set_precisions.f90 amos.f90 test_ZBESI.f90.

I came across the same issue. In my case, this was because I1MACH and D1MACH called from ZBESI.f returned a wrong answer. Using the file in
https://github.com/certik/fortran-utils/blob/master/src/legacy/amos/d1mach.f90
made it work.

Related

Moment of inertia in fortran [duplicate]

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.

Dynamic arrays f95

I am trying to understand how to use dynamic memory in f95.
I know that the following code in f2003 works.
program main
use pippo
implicit none
integer, allocatable :: arr(:)
call createDynamic(arr)
end program main
module pippo
contains
subroutine createDynamic(arr)
implicit none
integer, allocatable,dimension(:)::arr
integer :: i,n
n=10
allocate(arr(n))
do i=1,n
arr(i) = i
end do
end subroutine createDynamic
end module pippo
I would like to write a version in f95: what is the proper way to do it?
Your code us valid Fortran 95 + the ISO/IEC TR-15581 enhancements to allocatable arrays, which allowed allocatable dummy arguments.
In pure Fortran 95 you have to allocate the array in the main program or use pointers. However, it is year 2019, almost 2020. There is very little reason to use Fortran 95 without this TR. Or even not just using most of the widely supported Fortran 2008 features.

Reading real*8 variable with value 0 with real*4 results a large number in fortran without warning

Reading real*4 variable with value 0 with real*8 results a large number, sometimes without warning.
I'm not good at Fortran. I was just running a Fortran code I got from someone else, and it made a segmentation fault. While I was debugging it, I found that one of the subroutines is reading a variable with value 0 defined with real*8 as real*4 results a large value.
I tried to reproduce it with simple code, but compiler showed a warning for the argument mismatch. I had to nest codes to reproduce the suppressed warning in simple code, but I'm not sure what's the exact condition for suppressed warning.
Actually, for some reason, I'm suspecting it may be the problem of my compiler, as the code (not the example code, original code) ran fine on the PC of the person who gave me the code.
file hello.f:
implicit none
call sdo()
END
file test.f:
subroutine sdo()
implicit none
real*4 dsecs
dsecs=0
write(0,*) dsecs
call sd(dsecs)
return
end
file test2.f:
subroutine sd(dsecs)
implicit none
real*8 dsecs
write(0,*) dsecs
return
end
compilation and execution:
$ gfortran -o hello hello.f test.f test2.f
$ ./hello
Expected result:
0. 00000000
0. 0000000000000000
Actual results:
0. 00000000
-5.2153889789423361E+223
It is not the problem of the compiler. It is the problem of the code. Your code did issue a warning for me that you were doing something nefarious, as it should. The subroutine that thinks dsecs is 4 bytes long sent 4 bytes. The subroutine that thinks dsecs is 8 bytes long looked at 8 bytes. What's in the other 4 bytes? Who knows. How does it look like when the two get mixed together? Probably not what you want. It's like accidentally getting served a scoopful of half icecream and half garbage: unlikely to taste the way you thought.
This is one of those problems that are very simply solved with that classic joke: "Doctor, doctor, it hurts when I do this!" - "Then... don't do that."
EDIT: Sorry, I cheated. I didn't compile them as separate programs. When I do, I don't get warnings. This is also normal - at compilation step, you didn't specify how foreign subroutines look so it couldn't complain, and at linking step compiler doesn't check any more.

Code with syntax error in do loop compiles and gives wrong result

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

Variable strangely takes the value zero after the call of a subroutine

I have been facing some issues trying to convert a code previously compiled with compaq visual fortran 6.6 to gfortran.
Here is a specific problem I have met with gfortran :
There is a variable called "et" which takes the value 3E+10. Then the program calls a subroutine. "et" doesn't appear in the subroutine, but after coming back to the main program it has now the value 0.
When compliling with compaq visual fortran I didn't have this problem.
The code I am working on is a huge scientific program, so I put below only a small part of it :
c
c calculate load/unload modulus
c
500 t=(s1-s3)/2.
aa=1.00
if(iconeps.ne.1)bb=1.00
if(smean.lt.ap1) smean=ap1
if(xn.gt.0.000001) aa=(smean/atmp)**xn
if(iconeps.eq.1)go to 220
if(xm.gt.0.000001) bb=(smean/atmp)**xm
220 if(t.ge.0.99*sm1) go to 600
et=xku*aa*atmp+tt*tm1
if(iconeps.ne.1)bt=xkb*atmp*bb
go to 900
600 et=(xkl*aa*atmp+tt*tm1)*(1.0-rf*sr)**2
if(iconeps.ne.1)bt=xkb*atmp*bb
900 continue
btmax=17.0*et
btmin=0.33*et
if(iconeps.ne.1)then
tbt=(alf1+alf3*dtt)*dtt*(1.+vide)*tm2
btf=bt+tbt
bt=btf
endif
if(bt.lt.btmin) bt=btmin
if(bt.gt.btmax) bt=btmax
if(iconeps.eq.1)go to 1100
1000 continue
1050 if(mt.eq.mtyp4c)goto 1100
s=0.0
t=0.0
call shap4n(s,t,f,pfs,pft) ! Modification by NHV
call thick4n(s,t,xe,ye,thick)
call bmat4n(xe,ye,f,pfs,pft,b,detj,thick)
c calculate incremental strains
do 1300 i=1,4
temp=0.0
do 1200 j=1,8
1200 temp=temp+b(i,j)*disp(j)
1300 depi(i)=temp
epsv=0.0
do 1400 i=1,2
1400 epsv=epsv+depi(i)
epsv=epsv+depi(4)
ev=vide-(1.+vide)*epsv
if(ev.lt.0.0)ev=vide*.01
1100 continue
call perm(permws,xkw,coef,rw,tvisc,ev,vide,tt,pp)
: "et" keeps the good value until just before calling the subroutine "perm". Just after this subroutine it takes the value zero.
"et" isn't in any common block
This piece of code is part of a subroutine called by several different subroutines. What is even more strange is that when it is called in other parts of the code I doesn't have this problem ("et" keeps its value)
So if someone has ever met this kind of problem or have any idea about it I will be very gratefull
Perhaps you have a memory access error, such as an array bounds violation, or a mismatch between actual and dummy arguments. Are the interfaces of the subroutines explicit, such as being "used" from a module? Also try turning on compiler debugging options ... obviously subscript checking, but others might catch something. An extensive set for gfortran 4.5 or 4.6 is:
-O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fwhole-file -fcheck=all -std=f2008 -pedantic -fbacktrace
Subscript checking is included in fcheck=all
I had this problem. In my main program, I was using double precision but the numbers I calculated with in my subroutine were single precision. After I changed them to double it fixed the problem and I got actual values instead of 0.