Hey I am trying to get my LAPACK libraries to work and I have searched and searched but I can't seem to figure out what I am doing wrong.
I try running my code, and I get the following error
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x7FFB23D405F7
#1 0x7FFB23D40C3E
#2 0x7FFB23692EAF
#3 0x401ED1 in sgesv_
#4 0x401D0B in MAIN__ at CFDtest.f03:? Segmentation fault (core dumped)
I will paste my main code here, hopefully someone can help me with this problem.
****************************************************
PROGRAM CFD_TEST
USE MY_LIB
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
DIMENSION ET(0:10), VN(0:10), WT(0:10)
DIMENSION SO(0:10), FU(0:10), DMA(0:10,0:10)
DIMENSION DMA2(0:10,0:10), QN(0:10), WKSPCE(0:10)
INTEGER*8 :: pivot(10), inf
INTEGER*8 :: N
EXTERNAL SGESV
!SET THE PARAMETERS
SIGMA1 = 0.D0
SIGMA2 = 0.D0
TAU = 1.D0
EF = 1.D0
EXP = 2.71828182845904509D0
COST = EXP/(1.D0+EXP*EXP)
DO 1 N=2, 10
!COMPUATION OF THE NODES, WEIGHTS AND DERIVATIVE MATRIX
CALL ZELEGL(N,ET,VN)
CALL WELEGL(N,ET,VN,WT)
CALL DMLEGL(N,10,ET,VN,DMA)
!CONSTRUCTION OF THE MATRIX CORRESPONDING TO THE
!DIFFERENTIAL OPERATOR
DO 2 I=0, N
DO 2 J=0, N
SUM = 0.D0
DO 3 K=0, N
SUM = SUM + DMA(I,K)*DMA(K,J)
3 CONTINUE
OPER = -SUM
IF(I .EQ. J) OPER = -SUM + TAU
DMA2(I,J) = OPER
2 CONTINUE
!CHANGE OF THE ENTRIES OF THE MATRIX ACCORDING TO THE
!BOUNDARY CONDITIONS
DO 4 J=0, N
DMA2(0,J) = 0.D0
DMA2(N,J) = 0.D0
4 CONTINUE
DMA2(0,0) = 1.D0
DMA2(N,N) = 1.D0
!CONSTRUCTION OF THE RIGHT-HAND SIDE VECTOR
DO 5 I=1, N-1
FU(I) = EF
5 CONTINUE
FU(0) = SIGMA1
FU(N) = SIGMA2
!SOLUTION OF THE LINEAR SYSTEM
N1 = N + 1
CALL SGESV(N,N,DMA2,pivot,FU,N,inf)
DO 6 I = 0, N
FU(I) = SO(I)
6 CONTINUE
PRINT *, pivot
1 CONTINUE
RETURN
END PROGRAM CFD_TEST
*****************************************************
The commands I run to compile are
gfortran -c MY_LIB.f03
gfortran -c CFDtest.f03
gfortran MY_LIB.o CFDtest.o -o CFDtest -L/usr/local/lib -llapack -lblas
I ran the command
-fbacktrace -g -Wall -Wextra CFDtest
CFDtest: In function _fini':
(.fini+0x0): multiple definition of_fini'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o:/build/buildd/glibc-2.19/csu/../sysdeps/x86_64/crti.S:80: first defined here
CFDtest: In function data_start':
(.data+0x0): multiple definition ofdata_start'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o:(.data+0x0): first defined here
CFDtest: In function data_start':
(.data+0x8): multiple definition of__dso_handle'
/usr/lib/gcc/x86_64-linux-gnu/4.9/crtbegin.o:(.data+0x0): first defined here
CFDtest:(.rodata+0x0): multiple definition of _IO_stdin_used'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o:(.rodata.cst4+0x0): first defined here
CFDtest: In function_start':
(.text+0x0): multiple definition of _start'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o:(.text+0x0): first defined here
CFDtest: In function_init':
(.init+0x0): multiple definition of _init'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o:/build/buildd/glibc-2.19/csu/../sysdeps/x86_64/crti.S:64: first defined here
/usr/lib/gcc/x86_64-linux-gnu/4.9/crtend.o:(.tm_clone_table+0x0): multiple definition of__TMC_END'
CFDtest:(.data+0x10): first defined here
/usr/bin/ld: error in CFDtest(.eh_frame); no .eh_frame_hdr table will be created.
collect2: error: ld returned 1 exit status
You haven't posted your code for MY_LIB.f03 so we cannot compile CFDtest.f03 exactly as you have supplied it.
(As an aside, the usual naming convention is that f90 in a .f90 file is not supposed to imply the language version being targeted. Rather, .f90 denotes free format while .f is used for fixed format. By extension, your .f03 files would be better (i.e., more portable if) named as .f90.)
I commented out the USE MY_LIB line and ran your code through nagfor -u -c cfd_test.f90. The output, broken down, is
Extension: cfd_test.f90, line 13: Byte count on numeric data type
detected at *#8
Extension: cfd_test.f90, line 15: Byte count on numeric data type
detected at *#8
Byte counts are not portable. The kind value for an 8-byte integer is selected_int_kind(18). (Similarly you might like to use a kind(0.0d0) kind value for your double precision data.)
Error: cfd_test.f90, line 48: Implicit type for I
detected at 2#I
Error: cfd_test.f90, line 50: Implicit type for J
detected at 2#J
Error: cfd_test.f90, line 54: Implicit type for K
detected at 3#K
Error: cfd_test.f90, line 100: Implicit type for N1
detected at N1#=
You have these implicitly typed, which implies they are 4-byte (default) integers. You should probably declare these explicitly as 8-byte integers (using the 8-byte integer kind value above) if that's what you intend.
Questionable: cfd_test.f90, line 116: Variable COST set but never referenced
Questionable: cfd_test.f90, line 116: Variable N1 set but never referenced
Warning: cfd_test.f90, line 116: Unused local variable QN
Warning: cfd_test.f90, line 116: Unused local variable WKSPCE
You need to decide what you intend to do with these, or whether they are just deletable cruft.
With the implicit integers declared explicitly, there is further output
Warning: cfd_test.f90, line 116: Variable SO referenced but never set
This looks bad.
Obsolescent: cfd_test.f90, line 66: 2 is a shared DO termination label
Your DO loops would probably be better using the modern END DO terminators (not shared!)
Error: cfd_test.f90, line 114: RETURN is only allowed in SUBROUTINEs and FUNCTIONs
This is obviously easy to fix.
For the LAPACK call, one source of explicit interfaces for these routines is the NAG Fortran Library (through the nag_library module). Since your real data is not single precision, you should be using dgesv instead of sgesv. Adding USE nag_library, ONLY: dgesv and switching to call dgesv instead of sgesv, then recompiling as above, reveals
Incorrect data type INTEGER(KIND=4) (expected INTEGER) for argument N (no. 1) of DGESV
so you should indeed be using default (4-byte integers) - at least for the LAPACK build on your system, which will almost certainly be using 4-byte integers. Thus you might want to forget all about kinding your integers and just use the default integer type for all. Correcting this gives
Array supplied for scalar argument LDA (no. 4) of DGESV
so you do need to add this argument. Maybe pass size(DMA2,1)?
With this argument added to the call the code compiles successfully, but without the definitions for your *LEGL functions I couldn't go through any run-time testing.
Here is my modified (and pretty-printed) version of your program
Program cfd_test
! Use my_lib
! Use nag_library, Only: dgesv
Implicit None
Integer, Parameter :: wp = kind(0.0D0)
Real (Kind=wp) :: ef, oper, sigma1, sigma2, tau
Integer :: i, inf, j, k, n, sum
Real (Kind=wp) :: dma(0:10, 0:10), dma2(0:10, 0:10), et(0:10), fu(0:10), &
so(0:10), vn(0:10), wt(0:10)
Integer :: pivot(10)
External :: dgesv, dmlegl, welegl, zelegl
Intrinsic :: kind, size
! SET THE PARAMETERS
sigma1 = 0._wp
sigma2 = 0._wp
tau = 1._wp
ef = 1._wp
Do n = 2, 10
! COMPUATION OF THE NODES, WEIGHTS AND DERIVATIVE MATRIX
Call zelegl(n, et, vn)
Call welegl(n, et, vn, wt)
Call dmlegl(n, 10, et, vn, dma)
! CONSTRUCTION OF THE MATRIX CORRESPONDING TO THE
! DIFFERENTIAL OPERATOR
Do i = 0, n
Do j = 0, n
sum = 0._wp
Do k = 0, n
sum = sum + dma(i, k)*dma(k, j)
End Do
oper = -sum
If (i==j) oper = -sum + tau
dma2(i, j) = oper
End Do
End Do
! CHANGE OF THE ENTRIES OF THE MATRIX ACCORDING TO THE
! BOUNDARY CONDITIONS
Do j = 0, n
dma2(0, j) = 0._wp
dma2(n, j) = 0._wp
End Do
dma2(0, 0) = 1._wp
dma2(n, n) = 1._wp
! CONSTRUCTION OF THE RIGHT-HAND SIDE VECTOR
Do i = 1, n - 1
fu(i) = ef
End Do
fu(0) = sigma1
fu(n) = sigma2
! SOLUTION OF THE LINEAR SYSTEM
Call dgesv(n, n, dma2, size(dma2,1), pivot, fu, n, inf)
Do i = 0, n
fu(i) = so(i)
End Do
Print *, pivot
End Do
End Program
In general your development experience will be the most pleasant if you use as good a checking compiler as you can get your hands on and if you make sure you ask it to diagnose as much as it can for you.
As far as I can tell, there could be a number of problems:
Your integers with INTEGER*8 might be too long, maybe INTEGER*4 or simply INTEGER would be better
You call SGESV on double arguments instead of DGESV
Your LDA argument is missing, so your code should perhaps look like CALL DGESV(N,N,DMA2,N,pivot,FU,N,inf) but you need to check whether this is what you want.
Related
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 am currently writing a code to simulate particle collisions. I am trying to open as much files as there are particles (N) and then put the data for positions and velocities in each of these files for each step of the time integration (using Euler's method, but that is not relevant). For that, I tried using a do loop so it will open all the files I need - then I put all the data in them with a different do loop later - and then close them all.
I first tried just doing a do loop to open the files - but it gave errors of the type "file already open in another unit", so I did the following:
module parameters
implicit none
character :: posvel
integer :: i, j, N
real :: tmax
real, parameter :: tmin=0.0, pi=3.14159265, k=500.0*10E3, dt=10.0E-5, dx=10.0E-3, g=9.806, ro=1.5*10E3
real, dimension(:), allocatable :: xold, xnew, vold, vnew, m, F, r
end module parameters
PROGRAM Collision
use parameters
implicit none
write(*,*) 'Enter total number of particles (integer number):'
read(*,*) N
allocate(xold(N))
allocate(vold(N))
allocate(xnew(N))
allocate(vnew(N))
allocate(m(N))
allocate(F(N))
allocate(r(N))
xold(1) = 0.0
vold(1) = 0.0
m(1) = 6.283*10E-9
r(1) = 10E-4
xold(2) = 5.0
vold(2) = 0.0
m(2) = 6.283*10E-9
r(2) = 10E-4
write(*,*) 'Type total time elapsed for the simulation(real number):'
read(*,*) tmax
do i = 1, N
write(posvel,"(a,i3.3,a)") "posveldata",i,".txt"
open(unit=i,file=posvel, status="unknown")
end do
do i = 1, N
close(unit=i)
end do
END PROGRAM Collision
The last ten lines are the ones that regard to my problem.
That worked in codeblocks - it opened just the number of files I needed, but I'm actually using gfortran and it gives me and "end of record" error in the write statement.
How can I make it to execute properly and give me the N different files that I need?
P.S.: It is not a problem of compilation, but after I execute the program.
Your character string in the parameter module has only 1 character length, so it cannot contain the full file name. So please use a longer string, for example
character(100) :: posvel
Then you can open each file as
do i = 1, N
write(posvel,"(a,i0,a)") "posveldata",i,".txt"
open(unit=i,file=trim(posvel), status="unknown")
end do
Here, I have used the format i0 to automatically determine a proper width for integer, and trim() for removing unnecessary blanks in the file name (though they may not be necessary). The write statement can also be written more compactly as
write(posvel,"('posveldata',i0,'.txt')") i
by embedding character literals into the format specification.
The error message "End of record" comes from the above issue. This can be confirmed by the following code
character c
write(c,"(a)") "1"
print *, "c = ", c
write(c,"(a)") "23" !! line 8 in test.f90
print *, "c = ", c
for which gfortran gives
c = 1
At line 8 of file test.f90
Fortran runtime error: End of record
This means that while c is used as an internal file, this "file" does not have enough space to accommodate two characters (here "23"). For comparison, ifort14 gives
c = 1
forrtl: severe (66): output statement overflows record, unit -5, file Internal Formatted Write
while Oracle Fortran12 gives
c = 1
****** FORTRAN RUN-TIME SYSTEM ******
Error 1010: record too long
Location: the WRITE statement at line 8 of "test.f90"
Aborted
(It is interesting that Oracle Fortran reports the record to be "too long", which may refer to the input string.)
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 cant figure out whats my mistake I googled the problem took "implicit none" and declared eyery variable to integer I used but I still get the follwing errors:
main.f95:37.20:
e = Collatzf(i)
1
Error: Return type mismatch of function 'collatzf' at (1) (UNKNOWN/INTEGER(4))
main.f95:37.12:
e = Collatzf(i)
1
Error: Function 'collatzf' at (1) has no IMPLICIT type
Here is my Code:
INTEGER FUNCTION Collatzf(n)
IMPLICIT NONE
INTEGER :: n, z
z = 0
DO WHILE(n /= 1)
IF (MOD(n, 2) == 0) THEN
n = n / 2
ELSE
n = 3 * n + 1
END IF
z = z + 1
END DO
Collatzf = z
END FUNCTION Collatzf
PROGRAM ProjectEuler14
IMPLICIT NONE
INTEGER :: lsg, e, s, i
lsg = 0
e = 0
s = 0
i = 2
DO WHILE(i <= 1000000)
e = Collatzf(i)
IF(e > lsg) THEN
lsg = e
s = i
END IF
i = i + 1
END DO
WRITE(*, *) s, i
END PROGRAM ProjectEuler14
Thx :)
There is no declaration for the Collatzf function inside the main program.
Program units in Fortran have a separate compilation model - when compiling a program unit the compiler technically knows nothing about other program units, unless there are statements that give it explicit knowledge about those other units. So when compiling your main program (from the PROGRAM ... statement through to the END PROGRAM statement) the compiler has no idea what Collatzf is, even though the definition of that external function immediately preceded the main program. It cannot apply implicit typing rules because you have specified IMPLICIT NONE (a good thing), so hence you see the second error.
Provide a declaration of the type of Collatzf inside the main program. Better than that - provide an interface body for that function inside the main program. Even better than that again - make that function a module procedure, and then USE the module inside the main program.
lanH's answer is correct. Three suggested solutions are:
1) "Provide a declaration of the type of Collatzf inside the main program", which means adding
INTEGER :: Collatzf
statement to the variable declaration in PROGRAM ProjectEuler14.
2) "Provide an interface body for Collatzf function", which means means adding
INTERFACE
FUNCTION Collatzf (i)
INTEGER :: Collatzf
INTEGER, INTENT(IN) :: i
END FUNCTION Collatzf
END INTERFACE
statements to the variable declaration in "PROGRAM ProjectEuler14".
3) "Make that function a module procedure, and then USE the module inside the main program", which means creating a new file, named (for simplicity) "functions.f90":
MODULE functions
CONTAINS
INTEGER FUNCTION Collatzf(n)
IMPLICIT NONE
INTEGER :: n, z
z = 0
DO WHILE(n /= 1)
IF (MOD(n, 2) == 0) THEN
n = n / 2
ELSE
n = 3 * n + 1
END IF
z = z + 1
END DO
Collatzf = z
END FUNCTION Collatzf
END MODULE functions
Then compile functions.f90 first by e.g.:
gfortran -c functions.f90
and link the compiled "functions" module into your main program:
gfortran main.f90 functions.o
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.