# Should I use a Fortran module?

1. Aug 16, 2014

### sketos

Hello,

I want to create one file test.f95 where i can keep all my subroutines and use them whenever i create a new program
new.f95.

Is the modules the right way to do it?? because when i create a file lets say test.f95 with the module and one other with my main program (new.f95) when i compile test.f95 i get this :

/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o: In function _start':
(.text+0x20): undefined reference to main'
collect2: ld returned 1 exit status

And if i try to compile my main program (new.f95) i get this:

/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o: In function _start':
(.text+0x20): undefined reference to main'
collect2: ld returned 1 exit status

My programs are:

test.f95 ::

module module1
integer:: n
contains

recursive subroutine sub1(x)
integer,intent(inout):: x
integer:: y
y = 0
if (x < n) then
x = x + 1
y = x**2
print *, 'x = ', x,', y = ', y
call sub1(x)
print *, 'x = ', x,', y = ', y
end if
end subroutine sub1

end module module1

new.f95 ::

program main
use module1
integer:: x = 0
print *, 'Enter number of repeats'
call sub1(x)
end program main

2. Aug 16, 2014

### AlephZero

What commands did you use to compile the programs?

Code (Text):

gfortran new.f95 test.f95

works for me. Or if you want to compile the subroutines separately,
Code (Text):

gfortran -c test.f95
gfortran new.f95 test.o

Maybe the errors are because your IDE doesn't understand what you are doing. (Personally I tend to solve that problem by not using an IDE).

3. Aug 16, 2014

### sketos

i compile it using : f95 test.f95 -o test --> ./test

f95 new.f95 -o new -->./new

This doesnt work???

4. Aug 16, 2014

### Staff: Mentor

It doesn't work, because you are not compiling whole project, only part of it. Compiler has no way of knowing where the missing procedures are - you have to tell it explicitly where they are. Either by giving a list of Fortran sources in the command line, or by giving list of sources to compile and objects containing already compiled sources in the "link ready" format.

5. Aug 16, 2014

### sketos

So i have to do it the way AlephZero described???

6. Aug 16, 2014

### Staff: Mentor

Yes.

It is also possible to use the make utility, then you need to put the information about files in the makefile - but IMHO for small, two file projects it doesn't make sense.

7. Aug 16, 2014

### AlephZero

One extra comment on that: when you compile test.f95, you will create a "module interface file" called module1.mod. When the compiler reads the "use module1" statement in main.f95, it will automatically read module1.mod, or produce an error message if it can't find it. But the .mod file only contains information about the argument lists of the subroutines in the module, so the compiler can check you are calling them correctly. It doesn't contain the compiled code. You also have to tell the compiler to read test.o.

Note, if you have several modules, it is simpler to have the module name the same as the source file name, so the code for "module1" is in module1.f95, and compiling it creates module1.mod and module1.o.

Also, the Fortran 95 standard doesn't say how the module interface information should be stored, and some Fortran systems do store the module interface definition and the compiled code in the same file. But gfortan doesn't do that.

8. Aug 16, 2014

### Staff: Mentor

This doesn't work because 'test' does not contain a main program.

This doesn't work because, although 'new' does contain a main program, it does not contain the subroutine 'sub1'.

If you use the command:

f95 new.f95 test.f95 -o new

this should compile both source files, and link (combine) the output into 'new' which should be a complete executable program that you can run via the commad './new'.

Or, if you want to do the compiling and linking separately for some reason, you can do this:

f95 new.f95 -o new.o (creates a file 'new.o' which contains the compiled main program)
f95 test.f95 -o test.o (creates a file 'test.o' which contains the compiled module with the subroutine)
f95 new.o test.o -o new (links the two '.o' files and places the result in the executable 'new')

9. Aug 18, 2014

### sketos

Thank you all guys.

I have one last question:

When i compile my main program with the module (which contains one function and 2 subroutines) i get the following error:

/tmp/ccToz1RS.o: In function __statistictests_MOD_kstwo':
StatiTests.f95:(.text+0x208): undefined reference to probks_'
collect2: ld returned 1 exit status

are you guys familiar with what that means?? (my function name in probks and the module name is statistictests)

10. Aug 18, 2014

### AlephZero

Without seeing the code, and exactly what you did to compile it, we are just guessing.

11. Aug 18, 2014

### Staff: Mentor

'ld' is the "linker" utility that f95 (and most other compilers on Unix-like systems) uses to link compiled modules together into an executable program. The error message means that your program wants to use something named 'probks_', and 'ld' can't find it. It's probably a subroutine or function named 'probks' (with the compiler adding the '_' internally).

I can offer two guesses: (1) You've simply misspelled the name of one of your own subroutines when you call it. (2) Your program uses a subroutine or function named 'probks' from a third-party library, and you didn't specify the library when you tried to compile the program.

If it's (2), how you specify the library in the compilation command depends on how and where it's installed on your system.

12. Aug 18, 2014

### sketos

MY FILE ( StatiTests.f95) WHICH CONTAINS THE MODULE:

module StatisticTests

implicit none

contains

SUBROUTINE kstwo(data1,n1,data2,n2,d,prob)
INTEGER n1,n2
REAL d,prob,data1(n1),data2(n2)
!CU USES probks,sort
INTEGER j1,j2
REAL d1,d2,dt,en1,en2,en,fn1,fn2,probks
call sort(n1,data1)
call sort(n2,data2)
en1=n1
en2=n2
j1=1
j2=1
fn1=0.
fn2=0.
d=0.
1 if(j1.le.n1.and.j2.le.n2)then
d1=data1(j1)
d2=data2(j2)
if(d1.le.d2)then
fn1=j1/en1
j1=j1+1
endif
if(d2.le.d1)then
fn2=j2/en2
j2=j2+1
endif
dt=abs(fn2-fn1)
if(dt.gt.d)d=dt
goto 1
endif
en=sqrt(en1*en2/(en1+en2))
prob=probks((en+0.12+0.11/en)*d)
return
END

FUNCTION probks(alam)
REAL probks,alam,EPS1,EPS2
PARAMETER (EPS1=0.001, EPS2=1.e-8)
INTEGER j
REAL a2,fac,term,termbf
a2=-2.*alam**2
fac=2.
probks=0.
termbf=0.
do 11 j=1,100
term=fac*exp(a2*j**2)
probks=probks+term
if(abs(term).le.EPS1*termbf.or.abs(term).le.EPS2*probks)return
fac=-fac
termbf=abs(term)
11 continue
probks=1.
return
END

SUBROUTINE sort(n,arr)
INTEGER n,M,NSTACK
REAL arr(n)
PARAMETER (M=7,NSTACK=50)
INTEGER i,ir,j,jstack,k,l,istack(NSTACK)
REAL a,temp
jstack=0
l=1
ir=n
1 if(ir-l.lt.M)then
do 12 j=l+1,ir
a=arr(j)
do 11 i=j-1,1,-1
if(arr(i).le.a)goto 2
arr(i+1)=arr(i)
11 continue
i=0
2 arr(i+1)=a
12 continue
if(jstack.eq.0)return
ir=istack(jstack)
l=istack(jstack-1)
jstack=jstack-2
else
k=(l+ir)/2
temp=arr(k)
arr(k)=arr(l+1)
arr(l+1)=temp
if(arr(l+1).gt.arr(ir))then
temp=arr(l+1)
arr(l+1)=arr(ir)
arr(ir)=temp
endif
if(arr(l).gt.arr(ir))then
temp=arr(l)
arr(l)=arr(ir)
arr(ir)=temp
endif
if(arr(l+1).gt.arr(l))then
temp=arr(l+1)
arr(l+1)=arr(l)
arr(l)=temp
endif
i=l+1
j=ir
a=arr(l)
3 continue
i=i+1
if(arr(i).lt.a)goto 3
4 continue
j=j-1
if(arr(j).gt.a)goto 4
if(j.lt.i)goto 5
temp=arr(i)
arr(i)=arr(j)
arr(j)=temp
goto 3
5 arr(l)=arr(j)
arr(j)=a
jstack=jstack+2
if(jstack.gt.NSTACK)pause
if(ir-i+1.ge.j-l)then
istack(jstack)=ir
istack(jstack-1)=i
ir=j-1
else
istack(jstack)=j-1
istack(jstack-1)=l
l=i
endif
endif
goto 1
END

end module StatisticTests

AND MY MAIN PROGRAM:

program main

use StatisticTests

implicit none

integer i,n1,n2,n3
real pi,HI,Mfof,RA,DE,Vcdm,CDz
parameter(pi=3.1415,n1=3071,n2=1032,n3=2005)
real Z_obs1(n1),Z_obs2(n2),Z_obs3(n3)
real d12,d23,d31,prob12,prob23,prob31

open(unit=1,file="halo_cone_mock_lcdmw5_c2592_n1024.dat",status="old")
open(unit=2,file="halo_cone_mock_rpcdmw5_c2592_n1024.dat",status="old")

!n1=3071 !# of data-points for the ΛCDM
!n2=1032 !# of data-points for the RPCDM

do i=1,n1
end do

do i=1,n2
end do

call kstwo(Z_obs1,n1,Z_obs2,n2,d12,prob12)

print*,"The KS two-sample test fot the LCDM-RPCDM"
print*,
print*,d12,prob12

end program

FOR THE COMPLILE : f95 main.f95 StatiTests.f95 -o new

sorry for the long post :)

13. Aug 18, 2014

### SteamKing

Staff Emeritus
Suggestion for the OP: When posting source code, please use the
Code (Text):
tags around the source statements.  The [CODE] tags help preserve the formatting of the source file, which is lost if it is inserted directly into the Reply Box.

14. Aug 18, 2014

### AlephZero

I don't understand this yet.

If you remove the use of modules, the error message goes away.

But this minimal example compiles and runs OK:

Code (Text):

program test

use mymod

call sub(x)
print *,x
end

Code (Text):

module mymod

contains

subroutine sub(y)
x = 10
y = func(x)
end

function func(x)
func = 42 + x
end

end module mymod

One way to solve the mystery would be to add one thing at a time to the working example until it stop working, and then figure out why.

15. Aug 18, 2014

### Staff: Mentor

I've never used modules, but can you use 'implicit none' at the beginning of a module? I've always used it at the beginning of each subroutine or function.

16. Aug 18, 2014

### AlephZero

I never used IMPLICIT NONE that way either, but that's not the problem.

It seems like the compiler thinks you have declared probks twice: once by writing the actual function, and again in subroutine kstwo when you say

Code (Text):

REAL d1,d2,dt,en1,en2,en,fn1,fn2,probks

If you change that line to
Code (Text):

REAL d1,d2,dt,en1,en2,en,fn1,fn2

You can make my trivial example fail the same way, without IMPLICIT NONE. This fails:
Code (Text):

module mymod

contains

subroutine sub(y)
real x, y, func
x = 10
y = func(x)
end

function func(x)
real func, x
func = 42 + x
end

end module mymod

but this works:
Code (Text):

....
subroutine sub(y)
real x, y
....

I don't understand this. IMO either this is a very obscure feature of Fortran 95, or else it's a compiler bug. But at least we now know what to do about it!

Note, in F95 you can write "overloaded functions" similar to C++, where you have several functions with the same name and the compiler calls the correct one based on the type of the parameters passed to it. Maybe the "failed" version is somehow declaring two different functions with the sane name, but of course the link editor can only find one so it gives an error about the other one. But the "proper" way to use overloaded functions is write your own "interface" block between the "module" and "contains" statements, not let it happen by default.

Last edited: Aug 18, 2014
17. Aug 18, 2014

### sketos

I am truly thankful to you man !!