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.
Related
I would like to use FM package capabilities for the study of a problem in number theory.
I installed the package, compiled libraries, and ran the two test suites supplied, all without any problems.
I wrote test.f:
use fmzm
TYPE (IM), SAVE :: n
n = 0
WRITE(*,*) n
end
and compiled using
gfortran -c -O3 -Wall test.f
gfortran fmsave.o fm.o fmzm90.o test.o -o test
which returned no error or warning. But got disappointed by discovering the output:
./test
200000
The number 200000 appears to be a memory location for the variable n. I experimented a little, and if I change n to complex type (ZM) it outputs 200000, 199999. Similarly if I declare and initialize two variable instead of one.
If I change TYPE (IM), SAVE :: n to INTEGER n, and compile exactly as above, I get the expected 0 as output.
If I replace the code by
n = 0
do
n=n+1
if (n < 10) WRITE(*,*) n
end do
then the output 200000 repeats 9 times and then stops. So it is the WRITE function which only finds the location and not the value. PRINT does the same.
As Vladimir points out, unless you write out a value of a standard type, it seems you have to first convert to a string using a maneuver such as
str = im_format('i100', n)
str = adjustl(str)
str = trim(str)
print*, str
where the middle two lines can be left out.
I am converting f77 code to f90 code, and part of the code needs to sum over elements of a 3d matrix. In f77 this was accomplished by using 3 loops (over outer,middle,inner indices). I decided to use the f90 intrinsic sum (3 times) to accomplish this, and much to my surprise the answers differ. I am using the ifort compiler, have debugging, check-bounds, no optimization all turned on
Here is the f77-style code
r1 = 0.0
do k=1,nz
do j=1,ny
do i=1,nx
r1 = r1 + foo(i,j,k)
end do
end do
end do
and here is the f90 code
r = SUM(SUM(SUM(foo, DIM=3), DIM=2), DIM=1)
I have tried all sorts of variations, such as swapping the order of the loops for the f77 code, or creating temporary 2D matrices and 1D arrays to "reduce" the dimensions while using SUM, but the explicit f77 style loops always give different answers from the f90+ SUM function.
I'd appreciate any suggestions that help understand the discrepancy.
By the way this is using one serial processor.
Edited 12:13 pm to show complete example
! ifort -check bounds -extend-source 132 -g -traceback -debug inline-debug-info -mkl -o verify verify.f90
! ./verify
program verify
implicit none
integer :: nx,ny,nz
parameter(nx=131,ny=131,nz=131)
integer :: i,j,k
real :: foo(nx,ny,nz)
real :: r0,r1,r2
real :: s0,s1,s2
real :: r2Dfooxy(nx,ny),r1Dfoox(nx)
call random_seed
call random_number(foo)
r0 = 0.0
do k=1,nz
do j=1,ny
do i=1,nx
r0 = r0 + foo(i,j,k)
end do
end do
end do
r1 = 0.0
do i=1,nx
do j=1,ny
do k=1,nz
r1 = r1 + foo(i,j,k)
end do
end do
end do
r2 = 0.0
do j=1,ny
do i=1,nx
do k=1,nz
r2 = r2 + foo(i,j,k)
end do
end do
end do
!*************************
s0 = 0.0
s0 = SUM(SUM(SUM(foo, DIM=3), DIM=2), DIM=1)
s1 = 0.0
r2Dfooxy = SUM(foo, DIM = 3)
r1Dfoox = SUM(r2Dfooxy, DIM = 2)
s1 = SUM(r1Dfoox)
s2 = SUM(foo)
!*************************
print *,'nx,ny,nz = ',nx,ny,nz
print *,'size(foo) = ',size(foo)
write(*,'(A,4(ES15.8))') 'r0,r1,r2 = ',r0,r1,r2
write(*,'(A,3(ES15.8))') 'r0-r1,r0-r2,r1-r2 = ',r0-r1,r0-r2,r1-r2
write(*,'(A,4(ES15.8))') 's0,s1,s2 = ',s0,s1,s2
write(*,'(A,3(ES15.8))') 's0-s1,s0-s2,s1-s2 = ',s0-s1,s0-s2,s1-s2
write(*,'(A,3(ES15.8))') 'r0-s1,r1-s1,r2-s1 = ',r0-s1,r1-s1,r2-s1
stop
end
!**********************************************
sample output
nx,ny,nz = 131 131 131
size(foo) = 2248091
r0,r1,r2 = 1.12398225E+06 1.12399525E+06 1.12397238E+06
r0-r1,r0-r2,r1-r2 = -1.30000000E+01 9.87500000E+00 2.28750000E+01
s0,s1,s2 = 1.12397975E+06 1.12397975E+06 1.12398225E+06
s0-s1,s0-s2,s1-s2 = 0.00000000E+00-2.50000000E+00-2.50000000E+00
r0-s1,r1-s1,r2-s1 = 2.50000000E+00 1.55000000E+01-7.37500000E+00
First, welcome to StackOverflow. Please take the tour! There is a reason we expect a Minimal, Complete, and Verifiable example because we look at your code and can only guess at what might be the case and that is not too helpful for the community.
I hope the following suggestions helps you figure out what is going on.
Use the size() function and print what Fortran thinks are the sizes of the dimensions as well as printing nx, ny, and nz. As far as we know, the array is declared bigger than nx, ny, and nz and these variables are set according to the data set. Fortran does not necessarily initialize arrays to zero depending on whether it is a static or allocatable array.
You can also try specifying array extents in the sum function:
r = Sum(foo(1:nx,1:ny,1:nz))
If done like this, at least we know that the sum function is working on the exact same slice of foo that the loops loop over.
If this is the case, you will get the wrong answer even though there is nothing 'wrong' with the code. This is why it is particularly important to give that Minimal, Complete, and Verifiable example.
I can see the differences now. These are typical rounding errors from adding small numbers to a large sum. The processor is allowed to use any order of the summation it wants. There is no "right" order. You cannot really say that the original loops make the "correct" answer and the others do not.
What you can do is to use double precision. In extreme circumstances there are tricks like the Kahan summation but one rarely needs that.
Addition of a small number to a large sum is imprecise and especially so in single precision. You still have four significant digits in your result.
One typically does not use the DIM= argument, that is used in certain special circumstances.
If you want to sum all elements of foo, use just
s0 = SUM(foo)
That is enough.
What
s0 = SUM(SUM(SUM(foo, DIM=3), DIM=2), DIM=1)
does is that it will make a temporary 2D arrays with each element be the sum of the respective row in the z dimension, then a 1D array with each element the sum over the last dimension of the 2D array and then finally the sum of that 1D array. If it is done well, the final result will be the same, but it well eat a lot of CPU cycles.
The sum intrinsic function returns a processor-dependant approximation to the sum of the elements of the array argument. This is not the same thing as adding sequentially all elements.
It is simple to find an array x where
summation = x(1) + x(2) + x(3)
(performed strictly left to right) is not the best approximation for the sum treating the values as "mathematical reals" rather than floating point numbers.
As a concrete example to look at the nature of the approximation with ifort, we can look at the following program. We need to enable optimizations here to see effects; the importance of order of summation is apparent even with optimizations disabled (with -O0 or -debug).
implicit none
integer i
real x(50)
real total
x = [1.,(EPSILON(0.)/2, i=1, SIZE(x)-1)]
total = 0
do i=1, SIZE(x)
total = total+x(i)
print '(4F17.14)', total, SUM(x(:i)), SUM(DBLE(x(:i))), REAL(SUM(DBLE(x(:i))))
end do
end program
If adding up in strict order we get 1., seeing that anything smaller in magnitude than epsilon(0.) doesn't affect the sum.
You can experiment with the size of the array and order of its elements, the scaling of the small numbers and the ifort floating point compilation options (such as -fp-model strict, -mieee-fp, -pc32). You can also try to find an example like the above using double precision instead of default real.
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).
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.