Related
Let me just preface this by saying that I am very new to Fortran but familiar with Python. My research project however requires me to use some pre-written Fortran code, which at this moment wont compile on my pc. I am trying to understand why.
The actual code I am trying to compile is very long and probably not very illuminating, but I think I have managed to come up with a minimal example of where I think the issue is. Let's say I have a very simple module and subroutine as follows,
module arraycheck
implicit none
real*8, allocatable, dimension(:) :: x
contains
subroutine fillx
real*8, allocatable, dimension(:) :: x
allocate(x(5))
x(1) = 1
x(2) = 2
x(3) = 3
x(4) = 4
x(5) = 5
print*, x
end subroutine fillx
end module arraycheck
which I expect to simply create an array x, which when the subroutine fillx is called fills the array with the integers 1 to 5. My actual source contains something conceptually similar to this. Now I also have a main program as follows,
program main
use arraycheck
print*, x
call fillx
print*,x
end
My idea here would be that on the first print statement the variable x is still unallocated, so print returns nothing, and then on the second print statement x has been filled, so it should return the filled array.
However on both print statements nothing is returned. Now in my original source code something similar happens, which causes runtime to throw an error that an unallocated array was passed somewhere as an actual argument, which should have been allocated. It seems like the exact same thing happens as in my small example here.
So my question is, is the behaviour that I observe in my example here expected? And if it is, how can I alter the code to make it work in the way that I would want it to? If I know this I might better understand why the actual source doesn't work.
Just in case it is relevant, I am using gfortran on ubuntu.
Thanks!
You have too different xs. They do not have anything in common. One a module array and one array local to the subroutine. When you allocate the local array in the subroutine, it does not do anything to the other array in the module.
Also, you cannot print array that is not allocated. That is not standard conforming (undefined behaviour). Anything can happen. You should definitely enable all compiler checks when diagnosing problems. The compiler should complain about your code with those checks.
Remove the local array declaration and avoid referencing unallocated variables. Module procedures have access to module variables through host association.
module arraycheck
implicit none
real*8, allocatable, dimension(:) :: x
contains
subroutine fillx
allocate(x(5))
x(1) = 1
x(2) = 2
x(3) = 3
x(4) = 4
x(5) = 5
print*, x
end subroutine fillx
end module arraycheck
program main
use arraycheck
call fillx
print*,x
end
Also, real*8 is not standard Fortran, it is a non-standard extension. Fortran 90 and later uses the kind system instead.
Here are some other things which might be helpful - shown in UPPERCASE.
module arraycheck
USE ISO_C_BINDING, ONLY : C_Int32_t, C_DOUBLE
implicit none
PRIVATE
real(KIND=C_DOUBLE), allocatable, dimension(:), PUBLIC :: x
PUBLIC Creation_X, Destruction_X, FillX
contains
subroutine Creation_X(n)
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
INTEGER(KIND=C_Int32_t), INTENT(IN) :: n
allocate(x(n))
RETURN
end subroutine Creation_X
subroutine Destruction_X
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
IF(ALLOCATED(X)) DEALLOCATE(X)
RETURN
end subroutine Destruction_X
subroutine fillx
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
INTEGER(KIND=C_Int32_t) :: N
DO I= 1, SIZE(x)
x(I) = I
ENDDO
RETURN
end subroutine fillx
end module arraycheck
program main
use arraycheck
CALL Creation_X(5)
call fillx
print*,x
CALL Destruction_X
end
I have the following code:
Program function_as_an_array
implicit none
integer:: i
integer, parameter:: N=10
real*8:: x(N),y(N),f(N)
do i=1,N
x(i)=float(i)
end do
call func(f,N,x)
open(unit=20, file='test.dat')
do i=1,N
y(i)=f(i)
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
Subroutine func(f,N,x)
implicit none
integer i,N
real*8:: x(N),f(N)
do i=1,N
f(i)=x(i)**2
end do
end Subroutine func
I want to make the program indeed be meant for
"function as an arrray", i.e. I would like to replace the Subroutine func by a function f and get the same result (In the main program, I wish to keep a statement like y=f(x,N)). How can I do that?
There's no problem having a function return an array, as with this question and answer: the main issue is that you need the function to be in a module (or contained within the program) so that there's an automatic explicit interface: (Edit to add: or explicitly defining the interface as with Alexander Vogt's answer)
module functions
contains
function func(N,x)
implicit none
integer, intent(in) :: N
double precision, intent(in) :: x(N)
double precision, dimension(N) :: func
integer :: i
do i=1,N
func(i)=x(i)**2
end do
end function func
end module functions
Program function_as_an_array
use functions
implicit none
integer:: i
integer, parameter:: N=10
double precision:: x(N),y(N)
do i=1,N
x(i)=float(i)
end do
y = func(N,x)
open(unit=20, file='test.dat')
do i=1,N
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
But note that this sort of function - applying the same operation to every element in array - is somewhat more nicely done with a Fortran elemental function, defined to work simply on a scalar and Fortran will automatically map it over all elements of an array for you:
module functions
contains
elemental double precision function f(x)
implicit none
double precision, intent(in) :: x
f = x**2
end function f
end module functions
Program function_as_an_array
use functions
implicit none
integer:: i
integer, parameter:: N=10
double precision:: x(N),y(N)
do i=1,N
x(i)=float(i)
end do
y = f(x)
open(unit=20, file='test.dat')
do i=1,N
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
The nice thing about this is that it will now work on scalars, and arrays of any rank automatically. Wherever possible, it's good to have the compiler do your work for you.
This is working for me:
Program function_as_an_array
implicit none
integer:: i
integer, parameter:: N=10
real*8 :: x(N),y(N),f(N)
interface func
function func(x,N) result(f)
implicit none
integer N
real*8:: x(N),f(N)
end function
end interface
do i=1,N
x(i)=float(i)
end do
f = func(x,N)
open(unit=20, file='test.dat')
do i=1,N
y(i)=f(i)
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
function func(x,N) result(f)
implicit none
integer i, N
real*8:: x(N),f(N)
do i=1,N
f(i)=x(i)**2
end do
end function
You need to:
use result for an array-valued return variable [edit] or specify func as real*8:: func(N). See the comments for details.
use an explicit interface for external functions (or a module which has an implicit interface, see Jonathan Dursi's answer )
Then, you can directly assign the return value of the function to the array.
I am a low level Fortran programmer. I am trying to make subroutines as generic as possible and I wonder if I can send an information of which subroutine another subroutine should acces from a given information in the main program. For instance, if I have:
program main
use test
implicit none
real(8) X
end program main
And:
module test
contains
subroutine A (X)
real(8) X
X = 2*X
end subroutine A
subroutine B (X)
real(8) X
X = 3*X
end subroutine B
end module test
I would like to, given the subroutine name 'A' or 'B' in the main program, transfer this to a third subroutine C inside the module test, which in turn would make some calculations and use the transferred name to choose between A and B in its calculations.
I know if I build the calculations of that subroutine C inside the main program, I can use a procedure pointer to access either A or B subroutines. However, I need to have the subroutine C. So I guess I will have a subroutine C with built in procedure pointer and it will take the name given in the main program as an argument. But I do not know how to do that. Neither if it is possible. If it is not, is there any other way? I do not know, maybe the subroutine C reading a txt file associating the read name to the procedure pointer. But, how?
Thank you, in advance!
I think that what you want is this: you first define subroutines A and B
module ab_m
implicit none
contains
subroutine A(X)
real, intent(inout) :: X
X = 2 * X
end subroutine A
subroutine B(X)
real, intent(inout) :: X
X = 3 * X
end subroutine B
end module ab_m
Then subroutine C uses a dummy procedure, specified by an interface,
module c_m
implicit none
contains
subroutine C(sub,y)
interface
subroutine sub(p)
implicit none
real, intent(inout) :: p
end subroutine sub
end interface
real, intent(inout) :: y
y = y + 1
call sub(y)
end subroutine C
end module c_m
and the main program chooses what procedure to use in C:
program p
use ab_m
use c_m
implicit none
real :: z(2)
z = 1.0
call C(B, z(1))
call C(A, z(2))
write(*,*) z ! writes 6.0, 4.0 [ (1+1)*3, (1+1)*2) ]
end program p
I'm learning the basics of Fortran. I created a simple subroutine initializing a matrix:
program test
integer, parameter :: n = 1024
real :: a(n, n)
call init(a)
write (*, *) a(1, 1)
end program
subroutine init(a)
real :: a(n, n)
a(:, :) = 3.0
end subroutine
Then the output is 0.0 instead of expected 3.0. Apart from that, valgrind says that:
==7006== Conditional jump or move depends on uninitialised value(s)
==7006== at 0x400754: init_ (in /home/marcin/proj/mimuw/fortran/test)
==7006== by 0x4007A4: MAIN__ (in /home/marcin/proj/mimuw/fortran/test)
==7006== by 0x40083B: main (in /home/marcin/proj/mimuw/fortran/test)
Why? The n parameter is correctly recognized by the compiler and should be a global one.
I compiled the program with gfortran 6.3.1
n is not a global variable, it is a local variable of the main program.
The subroutine is a completely independent compilation unit from the main program and they do not share any information.
A subroutine can "see" other variables of the parent module, if it is a module procedure, or variables of a parent (host) procedure or program if it is an internal procedure.
Be sure to read about the structure of Fortran programs and use modules as much as possible. Prefer modules over internal procedures. You will see how to put the subroutine into a module or how to make it internal to the main program in the link.
I did not mention common blocks, just don't use them, they are obsolete. And rember to use implicit none in every compilation unit.
Assuming that you want it everywhere, then one uses a COMMON block in the f77 era, and a MODULE now.
I CAPITALISED most of the changes. And if there is no error gives a few ways to consider understanding N in the SUBROUTINE, and an ELEMENTAL FUNCTION would likely be worthwhile to try here too.
MODULE MyMODULE
integer, parameter :: n = 1024
END MODULE MyMODULE
!%%%%%%%%%%
program test
USE MyModule
IMPLICIT NONE
! done up in ˆmoduleˆ...! integer, parameter :: n = 1024
REAL, DIMENSION(n,n) :: A
CALL Alternative_Init(A, 3.3)
WRITE (*,*) a(1, 1)
CALL Alternative2_Init(A, n, 1.23)
WRITE (*,*) a(1, 1)
call init(a)
write (*, *) a(1, 1)
END PROGRAM TEST
!%%%%%%%%%%
subroutine init(a)
USE MyModule
IMPLICIT NONE
real :: a(n, n)
a(:, :) = 3.0
RETURN
END SUBROUTINE init
!%%%%%%%%%%
SUBROUTINE Alternative_Init(a, Val4A)
USE MyModule
IMPLICIT NONE
REAL, DIMENSION(:,:) , INTENT(INOUT) :: a
REAL , INTENT(IN ) :: Val4A
a(:, :) = Val4A
! or just... A = Val4A ! which does them all too.
RETURN
END SUBROUTINE Alternative_Init
!%%%%%%%%%%
SUBROUTINE Alternative2_Init(a, n, Val4A)
!!!! USE MyModule
IMPLICIT NONE
INTEGER , INTENT(IN ) :: n
REAL, DIMENSION(n,n) , INTENT( OUT) :: a
REAL , INTENT(IN ) :: Val4A
A = Val4A
RETURN
END SUBROUTINE Alternative2_Init
When testing for computer performance with different internal representation (kind), the code stays more or less the same, except the definition of the tested parameters (kind=1;kind=2). I have tried to build different modules.
module var_1
implicit none
real(8), allocatable :: x(:,:),xi(:,:),xt(:,:)
integer(kind=1), allocatable :: z(:,:)
end module var_1
module var_2
implicit none
real(8), allocatable :: x(:,:),xi(:,:),xt(:,:)
integer(kind=2), allocatable :: z(:,:)
end module var_2
Also there is a global module that defines the parameters that do not change:
module global
integer :: i,j,n,p,nProcessors,s,v,w,infodpotrf,infodpotri,mkl_get_max_threads
integer, dimension(3) :: ni = [100, 1000, 10000], pi = [100, 1000, 10000]
integer, dimension(5) :: nProcessorsi = [1, 2, 4, 6, 12]
real(8):: u,myone= 1.d0,t11,t22
real:: t2,t1
include 'omp_lib.h'
end module global
Than in program part we call subroutines defined later on:
program test
call matrix_multi_inv_1
call matrix_multi_inv_2
end program test
Subroutines:
subroutine matrix_multi_inv_1
use global
use var_1
open (unit=100,file="results.txt",status="unknown")
do s=1,5
nProcessors = nProcessorsi(s)
CALL OMP_SET_NUM_THREADS(nProcessors)
do v=1,3
n=ni(v)
do w=1,3
p=pi(w)
allocate(x(n,n),z(n,p),xi(n,n),xt(n,n))
do i=1,n
do j=1,p
call random_number(u)
z(i,j)=real(floor(u*3),8)
enddo
enddo
1000 format(3(a20),2(i10),2(f15.3),i10)
t11=omp_get_wtime()
call cpu_time(t1)
x=matmul(z,transpose(z))
t22=omp_get_wtime()
call cpu_time(t2)
write(100,1000) 'x_integer_kind_1', 'G_real_8', 'matmul', n, p, t22-t11,t2-t1, mkl_get_max_threads()
deallocate(x,z,xi,xt)
enddo
enddo
enddo
end subroutine matrix_multi_inv_1
subroutine matrix_multi_inv_2
use global
use var_1
open (unit=100,file="results.txt",status="unknown")
do s=1,5
nProcessors = nProcessorsi(s)
CALL OMP_SET_NUM_THREADS(nProcessors)
do v=1,3
n=ni(v)
do w=1,3
p=pi(w)
allocate(x(n,n),z(n,p),xi(n,n),xt(n,n))
do i=1,n
do j=1,p
call random_number(u)
z(i,j)=real(floor(u*3),8)
enddo
enddo
1000 format(3(a20),2(i10),2(f15.3),i10)
t11=omp_get_wtime()
call cpu_time(t1)
x=matmul(z,transpose(z))
t22=omp_get_wtime()
call cpu_time(t2)
write(100,1000) 'x_integer_kind_2', 'G_real_8', 'matmul', n, p, t22-t11,t2-t1, mkl_get_max_threads()
deallocate(x,z,xi,xt)
enddo
enddo
enddo
end subroutine matrix_multi_inv_2
And here comes the problem. Subroutines are exactly the same except for the call module part. I have tried to use a contain statement in the subroutine but this does not work if the inner subroutine is called. Also I have tried to use subroutine with attribute but my compiler reports an error:
A kind type parameter must be a compile-time constant.
Does anyone know a nice solution how to optimize the code. When 10 different variation of different internal representation is tested than this code becomes just too big.
Similar problem is usually solved by poor man templates using include`. You move the common part to another file and the just do
subroutine matrix_multi_inv_1
use var_1
include "common.f90"
end subroutine
subroutine matrix_multi_inv_2
use var_2
include "common.f90"
end subroutine
C preprocessor can be used for more power.
Why not source out the relevant code into a file print_huge.inc.F90 to be included into modules:
! No module ... required
interface print_huge
module procedure print_huge
end interface
contains
subroutine print_huge(a)
real(kind=mykind),intent(in) :: a
print *, huge(a)
end subroutine
! no end module
Then you can include this into different modules print_huge_N:
module print_huge_4
integer,parameter :: mykind = 4
include 'print_huge.inc.F90'
end module
module print_huge_8
integer,parameter :: mykind = 8
include 'print_huge.inc.F90'
end module
module print_huge_16
integer,parameter :: mykind = 16
include 'print_huge.inc.F90'
end module
Note, that each module has its own mykind defined!
For convenience you can make use of the interface defined to bundle the modules into one "super module" (inspired by the example in the book of Arjen Markus):
module print_huge_all
use print_huge_4
use print_huge_8
use print_huge_16
end module
Then your main application would simply look like:
program huge_program
use print_huge_all
real(kind=4) :: a1
real(kind=8) :: a2
real(kind=16) :: a3
call print_huge(a1)
call print_huge(a2)
call print_huge(a3)
end program
With the following output:
./a.out
3.40282347E+38
1.7976931348623157E+308
1.18973149535723176508575932662800702E+4932
The subroutine resides in the include file and does not need to be adjusted to all kinds. Of course, you could directly access all modules directly and/or "rename" the subroutines using the => operator.