I am using a computational fluid dynamics software that is compiled with gfortran version 4.8.5 on Ubuntu 16.04 LTS. The software can be compiled with either single precision or double precision and the -O3 optimization option. As I do not have the necessary computational resources to run the CFD software on double precision I am compiling it with single precision and the following options
ffpe-trap=invalid,zero,overflow
I am getting a SIGFPE error on a line of code that contains the asin function-
INTEGER, PARAMETER :: sp = SELECTED_REAL_KIND( 6, 37) !< single precision
INTEGER, PARAMETER :: wp = sp
REAL(KIND=wp) zsm(:,:)
ela(i,j) = ASIN(zsm(ip,jp))
In other words the inverse sin function and this code is part of a doubly nested FOR loop with jp and ip as the indices. Currently the software staff is unable to help me for various other reasons and so I am trying to debug this on my own. The SIGFPE error is only being observed in the single precision compilation not double precision compilation.
I have inserted the following print statements in my code prior to the line of code that is failing i.e. the asin function call. Would this help me with unraveling the problem that I am facing ? This piece of code is executed for every time step and it is occurring after a series of time steps. Alternatively what other steps can I do to help me fix this problem ? Would adding "precision" to the compiler flag help ?
if (zsm(ip,jp) >= 1.0 .or. zsm(ip,jp) <= -1.0) then
print *,zsm(ip,jp),ip,jp
end if
EDIT
I took a look at this answer Unexpected behavior of asin in R and I am wondering whether I could do something similar in fortran i.e. by using the max function. If it goes below -1 or greater than 1 then round it off in the proper manner. How can I do it with gfortran using the max function ?
On my desktop the following program executes with no problems(i.e. it has the ability to handle signed zeros properly) and so I am guessing the SIGFPE error occurs with either the argument greater than 1 or less than -1.
program testa
real a,x
x = -0.0000
a = asin(x)
print *,a
end program testa
We have min and max functions in Fortran, so I think we can use the same method as in the linked page, i.e., asin( max(-1.0,min(1.0,x) ). I have tried the following test with gfortran-4.8 & 7.1:
program main
implicit none
integer, parameter :: sp = selected_real_kind( 6, 37 )
integer, parameter :: wp = sp
! integer, parameter :: wp = kind( 0.0 )
! integer, parameter :: wp = kind( 0.0d0 )
real(wp) :: x, a
print *, "Input x"
read(*,*) x
print *, "x =", x
print *, "equal to 1 ? :", x == 1.0_wp
print *, asin( x )
print *, asin( max( -1.0_wp, min( 1.0_wp, x ) ) )
end
which gives with wp = sp (or wp = kind(0.0) on my computer)
$ ./a.out
Input x
1.00000001
x = 1.00000000
equal to 1 ? : T
1.57079625 (<- 1.5707964 for gfortran-4.8)
1.57079625
$ ./a.out
Input x
1.0000001
x = 1.00000012
equal to 1 ? : F
NaN
1.57079625
and with wp = kind(0.0d0)
$ ./a.out
Input x
1.0000000000000001
x = 1.0000000000000000
equal to 1 ? : T
1.5707963267948966
1.5707963267948966
$ ./a.out
Input x
1.000000000000001
x = 1.0000000000000011
equal to 1 ? : F
NaN
1.5707963267948966
If it is necessary to modify a lot of asin(x) and the program relies on a C or Fortran preprocessor, it may be convenient to define some macro like
#define clamp(x) max(-1.0_wp,min(1.0_wp,x))
and use it as asin( clamp(x) ). If we want to remove such a modification, we can simply change the definition of clamp() as #define clamp(x) (x). Another approach may be to define some asin2(x) function that limits x to [-1,1] and replace the built-in asin by asin2 (either as a macro or a Fortran function).
Related
I am making a small code that will read numbers from 2.txt which is bunch of random real numbers, save it in a 2d array and pass it on the information to a subroutine. In the subroutine, I am assigning a particular dimension of this array to another matrix to save this for future calculation.
implicit none
double precision, allocatable :: x1(:,:)
integer :: nstep, nheatoms, k, i, j
open(unit=999,file="2.txt",status="old")
nstep = 5
nheatoms = 2
allocate(x1(3,nheatoms))
do k = 1, nstep
do i = 1, 3
do j = 1, nheatoms
read(999,*) x1(i,j)
end do
read(999,*)
end do
call diffusion(nstep,nheatoms,x1)
end do
stop
end
subroutine diffusion(nstep,nheatoms,qhecent)
implicit none
integer, intent (in) :: nheatoms, nstep
double precision :: qhecent(3,nheatoms)
integer :: j
double precision, allocatable :: qhestep(:,:)
integer :: nstepdiff, ncross
integer, save :: l = 0
double precision :: diff
l = l + 1
allocate(qhestep(nstep,nheatoms))
do j = 1, nheatoms
qhestep(l,j) = qhecent(3,j)
end do
if (l .gt. 1) then
do j = 1, nheatoms
write(*,*)qhestep(l,j), qhestep(l-1,j)
end do
end if
end subroutine
The 2.txt file is as follows:
1.0
2.1
3.2
-1.1
-2.2
-3.3
5.0
3.5
4.4
1.9
2.1
1.5
6.0
3.5
4.4
1.9
2.8
2.5
6.0
3.5
4.4
1.9
2.1
3.2
6.0
3.5
4.4
1.9
-4.3
7.9
Now if I compile with gfortran, most of the time I obtain the output as:
2.1000000000000001 -2.2000000000000002
1.5000000000000000 -3.2999999999999998
2.7999999999999998 2.1000000000000001
2.5000000000000000 1.5000000000000000
2.1000000000000001 2.7999999999999998
3.2000000000000002 2.5000000000000000
-4.2999999999999998 2.1000000000000001
7.9000000000000004 3.2000000000000002
which is expected. But if I run the code several times, an unknown number appear in the output, such as the example:
2.1000000000000001 -2.2000000000000002
1.5000000000000000 -3.2999999999999998
2.7999999999999998 1.2882297539194267E-231
2.5000000000000000 0.0000000000000000
2.1000000000000001 2.7999999999999998
3.2000000000000002 2.5000000000000000
-4.2999999999999998 2.1000000000000001
7.9000000000000004 3.2000000000000002
If I compile with ifort, then I obtain the output that have two zeros, which is wrong.
2.10000000000000 -2.20000000000000
1.50000000000000 -3.30000000000000
2.80000000000000 0.000000000000000E+000
2.50000000000000 0.000000000000000E+000
2.10000000000000 2.80000000000000
3.20000000000000 2.50000000000000
-4.30000000000000 2.10000000000000
7.90000000000000 3.20000000000000
I must stress that compiling on ifort most of the time gives correct results as in the case for gfortran. I am on a Mac OS High Sierra.
Thanks in advance.
Both compilers should give garbage results, as you are allocating qhestep in diffusion for each DO k loop. On exiting diffusion, qhestep is deallocated, so the accumulated information should be lost. That ifort returns the same heap address for qhestep on each call is misleading.
To overcome the problem, you should use allocate (qhestep(nstep,nheatoms)) before entering the DO k loop, then transfer the accumulation array in call diffusion.
That ifort gives your expected result is unfortunate, as it disguises a significant logic error. Each ALLOCATE basically provides a new memory location for the array.
You also provide no error tests when reading the file. I would recommend using iostat= for the reads and also report the data as it is read.
In summary, your approach gives the wrong result, which both compilers provide. The ifort results you provided are also wrong in some cases, but correct in others, which is misleading.
program hello
real(kind=8) :: x
x=1.000001234567890
Write(*,'(F10.11)') X
end program Hello
How exactly does the write statement work? I have tried several combination but can't figure it out. And what if I don't know a priori how many decimals a variable has? How can I just print all the number to the last decimal point?
The following program will print floating-point numbers to standard output without losing any precision.
program main
use ISO_Fortran_env, only: &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
! Explicit typing only
implicit none
! Variable declarations
integer, parameter :: SP = selected_real_kind(p=6, r=37)
integer, parameter :: DP = selected_real_kind(p=15, r=307)
real (SP) :: single
real (DP) :: double
single = 1.000001234567890_SP
double = 1.000001234567890_DP
write( stdout, '(e13.6e2)') single
write( stdout, '(e23.15e3)') double
write( stdout, '(/4a/)') &
' This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
Take note of how the kind parameters SP and DP are employed to control precision in a portable manner. This program yields:
0.100000E+01
0.100000123456789E+001
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -std=f2008ts
You main problem was in 'X.Y' that X is the total length, and Y is length to the right of the decimal point. So X > Y, and in your case by 2... Which should be "13.11".
PROGRAM Hello
IMPLICIT NONE
REAL(kind=8) :: x !Some suggest DOUBLE
x=1.000001234567890
WRITE(*,5) x
5 FORMAT('x=',F14.11)
WRITE(*,6) x !This make be better for you...
6 FORMAT('x=',0PE22.11) !This make be better for you...
END PROGRAM Hello
I am now running a program for a certain iterations. The time step is 0.01. I want to write some information when a specific time is reached. For example:
program abc
implicit none
double precision :: time,step,target
integer :: x
time = 0.d0
step = 0.01
target = 5.d0
do x = 1,6000
time = time + step
"some equations here to calculate the model parameters"
if(time.eq.target)then
write(*,*) "model parameters"
endif
enddo
However, "time" never equals to 1.0 or 2.0 or etc. It shows like "0.999999866" instead of "1.0" and "1.99999845" instead of "2.0".
Although I can use integer "x" to define when to write the information, I prefer to use the time step. Also, I may want to change the time step (0.01/0.02/0.05/etc) or target (5.0/6.0/8.0/etc).
Does anyone knows how to fix this? Thanks ahead.
You have now discovered floating point arithmetic! Just ensure that the time is sufficiently close to the target.
if(abs(time-target) < 0.5d0*step ) then
...
should do the trick.
Floating point arithmetic is not perfect and your variables are always exact up to a certain machine error, depending on your variables' number format (32, 64, 128 bit). The following example illustrates well this characteristic:
PROGRAM main
USE, INTRINSIC :: ISO_FORTRAN_ENV, qp => real128
IMPLICIT NONE
REAL(qp) :: a, b, c
a = 128._qp
b = a/120._qp + 1
c = 120._qp*(b-1)
PRINT*, "a = ", a
PRINT*, "c = ", c
END PROGRAM main
Here is the output to this program with gfortran v.4.6.3:
a = 128.00000000000000000
c = 127.99999999999999999
I have a code in Fortran IV that I need to run. I was told to try to compile it in Fortran 77 and fix the error. So I named the file with a .f extension and tried to compile it with gfortran. I got the next error referring to the Fortran IV function copied below:
abel.f:432.24:
REAL FUNCTION DGDT*8(IX,NV,XNG,FNG,GNG,X)
1
Error: Expected formal argument list in function definition at (1)
Since I'm not too familiar with Fortran I'd appreciate if someone can tell me how to fix this problem .
REAL FUNCTION DGDT*8(IX,NV,XNG,FNG,GNG,X) AAOK0429
C AAOK0430
C THIS SUBROUTINE COMPUTES THE VALUE OF THE DERIVATIVE OF THE AAOK0431
C G-FUNCTION FOR A SLIT TRANSMISSION FUNCTION GIVEN BY A AAOK0432
C PIECE-WISE CUBIC SPLINE , WHOSE PARAMETERS ARE AAOK0433
C CONTAINED IN XNG,FNG AND GNG. AAOK0434
C AAOK0435
IMPLICIT REAL*8(A-H,O-Z) AAOK0436
C AAOK0437
C ALLOWABLE ROUNDING ERROR ON POINTS AT EXTREAMS OF KNOT RANGE AAOK0438
C IS 2**IEPS*MAX(!XNG(1)!,!XNG(NV)!). AAOK0439
INTEGER*4 IFLG/0/,IEPS/-50/ AAOK0440
DIMENSION XNG(1),FNG(1),GNG(1) AAOK0441
C AAOK0442
C TEST WETHER POINT IN RANGE. AAOK0443
IF(X.LT.XNG(1)) GO TO 990 AAOK0444
IF(X.GT.XNG(NV)) GO TO 991 AAOK0445
C AAOK0446
C ESTIMATE KNOT INTERVAL BY ASSUMING EQUALLY SPACED KNOTS. AAOK0447
12 J=DABS(X-XNG(1))/(XNG(NV)-XNG(1))*(NV-1)+1 AAOK0448
C ENSURE CASE X=XNG(NV) GIVES J=NV-1 AAOK0449
J=MIN0(J,NV-1) AAOK0450
C INDICATE THAT KNOT INTERVAL INSIDE RANGE HAS BEEN USED. AAOK0451
IFLG=1 AAOK0452
C SEARCH FOR KNOT INTERVAL CONTAINING X. AAOK0453
IF(X.LT.XNG(J)) GO TO 2 AAOK0454
C LOOP TILL INTERVAL FOUND. AAOK0455
1 J=J+1 AAOK0456
11 IF(X.GT.XNG(J+1)) GO TO 1 AAOK0457
GO TO 7 AAOK0458
2 J=J-1 AAOK0459
IF(X.LT.XNG(J)) GO TO 2 AAOK0460
C AAOK0461
C CALCULATE SPLINE PARAMETERS FOR JTH INTERVAL. AAOK0462
7 H=XNG(J+1)-XNG(J) AAOK0463
Q1=H*GNG(J) AAOK0464
Q2=H*GNG(J+1) AAOK0465
SS=FNG(J+1)-FNG(J) AAOK0466
B=3D0*SS-2D0*Q1-Q2 AAOK0467
A=Q1+Q2-2D0*SS AAOK0468
C AAOK0469
C CALCULATE SPLINE VALUE. AAOK0470
8 Z=(X-XNG(J))/H AAOK0471
C TF=((A*Z+B)*Z+Q1)*Z+FNG(J) AAOK0472
C TG=((3.*A*Z+2.*B)*Z+Q1)/H AAOK0473
C DGDT=(TG-TF/X)/X AAOK0474
DGDT=(3.*A*Z*Z+2.*B*Z+Q1)/H AAOK0475
RETURN AAOK0476
C TEST IF X WITHIN ROUNDING ERROR OF XNG(1). AAOK0477
990 IF(X.LE.XNG(1)-2D0**IEPS*DMAX1(DABS(XNG(1)),DABS(XNG(NV)))) GO AAOK0478
1 TO 99 AAOK0479
J=1 AAOK0480
GO TO 7 AAOK0481
C TEST IF X WITHIN ROUNDING ERROR OF XNG(NV). AAOK0482
991 IF(X.GE.XNG(NV)+2D0**IEPS*DMAX1(DABS(XNG(1)),DABS(XNG(NV)))) GO AAOK0483
1 TO 99 AAOK0484
J=NV-1 AAOK0485
GO TO 7 AAOK0486
99 IFLG=0 AAOK0487
C FUNCTION VALUE SET TO ZERO FOR POINTS OUTSIDE THE RANGE. AAOK0488
DGDT=0D0 AAOK0489
RETURN AAOK0490
END AAOK0491
This doesn't look so bad. Modern compilers still accept the real*8 syntax although it isn't standard. So you should (as mentioned) replace the line
REAL FUNCTION DGDT*8(IX,NV,XNG,FNG,GNG,X) AAOK0429
with
REAL*8 FUNCTION DGDT(IX,NV,XNG,FNG,GNG,X) AAOK0429
which compiled successfully for me using gfortran 4.6.2 using gfortran -c DGDT.f.
Good luck, and be on the lookout for other problems. Just because the code compiles does not mean it is running the same way it was designed!
Not really an answer, see the one from Ross. But I just can't stand the requirement for fixed form. Here is how this code probably would look like in F90 with free form:
function DGDT(IX, NV, XNG, FNG, GNG, X)
! THIS FUNCTION COMPUTES THE VALUE OF THE DERIVATIVE OF THE
! G-FUNCTION FOR A SLIT TRANSMISSION FUNCTION GIVEN BY A
! PIECE-WISE CUBIC SPLINE, WHOSE PARAMETERS ARE
! CONTAINED IN XNG,FNG AND GNG.
implicit none
integer, parameter :: rk = selected_real_kind(15)
integer :: ix, nv
real(kind=rk) :: dgdt
real(kind=rk) :: xng(nv)
real(kind=rk) :: fng(nv)
real(kind=rk) :: gng(nv)
real(kind=rk) :: x
! ALLOWABLE ROUNDING ERROR ON POINTS AT EXTREAMS OF KNOT RANGE
! IS 2**IEPS*MAX(!XNG(1)!,!XNG(NV)!).
integer, parameter :: ieps = -50
integer, save :: iflg = 0
integer :: j
real(kind=rk) :: tolerance
real(kind=rk) :: H
real(kind=rk) :: A, B
real(kind=rk) :: Q1, Q2
real(kind=rk) :: SS
real(kind=rk) :: Z
tolerance = 2.0_rk**IEPS * MAXVAL(ABS(XNG([1,NV])))
! TEST WETHER POINT IN RANGE.
if ((X < XNG(1) - tolerance) .or. (X > XNG(NV) + tolerance)) then
! FUNCTION VALUE SET TO ZERO FOR POINTS OUTSIDE THE RANGE.
iflg = 0
DGDT = 0.0_rk
return
end if
! ESTIMATE KNOT INTERVAL BY ASSUMING EQUALLY SPACED KNOTS.
J = abs(x-xng(1)) / (xng(nv)-xng(1)) * (nv-1) + 1
! ENSURE CASE X=XNG(NV) GIVES J=NV-1
J = MIN(J,NV-1)
! INDICATE THAT KNOT INTERVAL INSIDE RANGE HAS BEEN USED.
IFLG = 1
! SEARCH FOR KNOT INTERVAL CONTAINING X.
do
if ( (x >= xng(j)) .or. (j==1) ) EXIT
j = j-1
! LOOP TILL INTERVAL FOUND.
end do
do
if ( (x <= xng(j+1)) .or. (j==nv-1) ) EXIT
j = j+1
! LOOP TILL INTERVAL FOUND.
end do
! CALCULATE SPLINE PARAMETERS FOR JTH INTERVAL.
H = XNG(J+1) - XNG(J)
Q1 = H*GNG(J)
Q2 = H*GNG(J+1)
SS = FNG(J+1) - FNG(J)
B = 3.0_rk*SS - 2.0_rk*Q1 - Q2
A = Q1 + Q2 - 2.0_rk*SS
! CALCULATE SPLINE VALUE.
Z = (X-XNG(J))/H
DGDT = ( (3.0_rk*A*Z + 2.0_rk*B)*Z + Q1 ) / H
end function DGDT
Note, I did not test this in any way, also there might be some wrong guesses in there, like that ieps should be a constant. Also, I am not so sure about iflg, and the ix argument does not appear to be used at all. So I might got something wrong. For the tolerance it is better to use a factor instead of a difference and a 2.**-50 will not change the value for a the maxval in a double precision number here. Also note, I am using some other F90 features besides the free form now.
DISCLAIMER: Just mentioning a possible solution here, not recommending it...
As much as all other answers are valid and that supporting some Fortran IV code as is is a nightmare, you still might want / need to avoid touching it as much as possible. And since Fortran IV had some strange behaviours when it comes to loops for example (with loops always cycled at least once IINM), using a "proper" Fortran IV compiler might be a "good" idea.
Anyway, all this to say that the Intel compiler for example, supports Fortran IV natively with the -f66 compiler switch, and I'm sure other compilers do as well. This may be worth checking.
I am working on getting a raytracing code working and I think I may have isolated the problem. I am new to working with Fortran 77, but would like to gain more experience using this language (even if it is dated). I have some EQUIVALENCE statements in one of the subroutines that may be used to pipe variables into the subroutine (this could be half the problem right here).
The subroutine:
c s/r qparxdp
SUBROUTINE QPARAB PARA001
implicit real*8 (a-h, o-z)
character*8 modx, id
C PLAIN PARABOLIC OR QUASI-PARABOLIC PROFILE PARA002
C W(104) = 0. FOR A PLAIN PARABOLIC PROFILE PARA003
C = 1. FOR A QUASI-PARABOLIC PROFILE PARA004
COMMON /XX/ MODX(2),X,PXPR,PXPTH,PXPPH,PXPT,HMAX PARA005
COMMON R(6) /WW/ ID(10),W0,W(400) PARA006
EQUIVALENCE (EARTHR,W(2)),(F,W(6)),(FC,W(101)),(HM,W(102)), PARA007
1 (YM,W(103)),(QUASI,W(104)),(PERT,W(150)) PARA008
data ipass / 0 /
ENTRY ELECTX PARA010
print*, W(2), W(6), W(101), W(102), W(103), W(104), W(150)
print*, ' Electx W(6), f ', F, EARTHR, FC, HM, YM, QUASI, PERT, ipass
ipass = ipass + 1
if(ipass.gt.10000) ipass = 2
if(ipass.eq.1) return
modx(1) = 'qparab'
HMAX=HM PARA011
x = 0.d0
pxpr = 0.d0
pxpth = 0.d0
pxpph = 0.d0
H=R(1)-EARTHR PARA013
if(f.le.0.d0) print*, ' YM', YM
FCF2=(FC/F)**2 PARA014
CONST=1.d0 PARA015
IF (QUASI.EQ.1.d0) CONST=(EARTHR+HM-YM)/R(1) PARA016
Z=(H-HM)/YM*CONST PARA017
X=dMAX1(0.d0,FCF2*(1.d0-Z*Z)) PARA018
print*, 'X in qparx', X, Z
IF (X.EQ.0.d0) GO TO 50 PARA019
IF (QUASI.EQ.1.d0) CONST=(EARTHR+HM)*(EARTHR+HM-YM)/R(1)**2 PARA020
PXPR=-2.d0*Z*FCF2/YM*CONST PARA021
50 IF (PERT.NE.0.d0) CALL ELECT1 PARA022
RETURN PARA023
END PARA024-
Immediately before the subroutine or entry ELECTX is called I placed some print statements in the RINDEX Subroutine/Entry.
I check a few of the inputs immediately before the call of RINDEX
ENTRY RINDEX
write(*,*), 'Starting Rindex in ahnwfnc', F
if(ray.eq.0.d0.and.ipass.eq.0) print*, ' no magnetic field'
ipass = 1
OM=PIT2*1.d6*F
C2=C*C
K2=KR*KR+KTH*KTH+KPH*KPH
OM2=OM*OM
VR =C/OM*KR
VTH=C/OM*KTH
VPH=C/OM*KPH
write(*,*), OM, C2, K2, OM2, VR, VTH, VPH, F
CALL ELECTX
What I get out of this little section of code is:
fstep,fbeg,fend 1. 7. 8.
fbeg,fstep,f 7. 1. 0.
f 7. 7.
f before Rindex 7.
Starting Rindex in ahnwfnc 7.
43982297.2 8.98755431E+10 1. 1.93444246E+15 0.00640514066 0.00231408417
0.000282636641 7.
0. 0. 0. 0. 0. 0. 0.
Electx W(6),f 0. 0. 0. 0. 0. 0. 0. 1
So this is a longwinded way of asking - what is going on? I expected the variables like f, for example, to be passed into the subroutine QPARAB, so when I print in the subroutine, I'd expect to see F = 7. I am probably fundamentally misunderstanding something simple. As I have mentioned, the fact that I can't seem to get variables like F into the subroutine QPARAB is actually a big issue because the following calculations come out to 0s or NaNs. I would expect it to have some value. So maybe the data isn't getting in somehow? Everything else (at this point) seems to be working, to some degree.
Where this code comes from:
And I am using a small shell script (this could be a total mess):
g77 -c -O3 raytr_dp.for readw_dp.for trace_dp.for reach_dp.for backup_d.for dummy.for \
polcar_d.for printr_d.for rkam_dp.for hamltn_d.for ahwfnc_d.for \
qparxdp.for dipoly_d.for spoints.for ggm_dp.for secnds.for
g77 -o main -O3 raytr_dp.o readw_dp.o trace_dp.o reach_dp.o backup_d.o dummy.o \
polcar_d.o printr_d.o rkam_dp.o hamltn_d.o ahwfnc_d.o \
qparxdp.o dipoly_d.o spoints.o ggm_dp.o secnds.o
The g77 routines I am using were downloaded at: http://hpc.sourceforge.net/ and finally I get the same error using gfortran,
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/local/gfortran/libexec/gcc/x86_64-apple-darwin13/4.9.0/lto-wrapper
Target: x86_64-apple-darwin13
Thread model: posix
gcc version 4.9.0 (GCC)
Subroutine QPARAB takes no arguments, e.g. nothing is passed to it. It loads the following variables from common blocks (variables shared between scope) MODX, X, PXPR, PXPTH, PXPPH, PXPT, HMAX, ID, W0, and W. Additionally it declares local scope variables modx and id and then assigns implicit typing to all undeclared variables (which are local in scope).
Your variable of interest, F is equivalent to writing W(6). This says that implicit variable F (type real*8) must have the same memory location as W(6). F isn't passed into this subroutine, it is a name local to the subroutine that is really a specific array member of W. If you want to pass a value into the subroutine into F, you need to set the variable W(6) prior to calling the subroutine. Note that in order to do this you will need W in scope and thus you will need the /WW/ common block referenced in the subroutine you are calling from.