How to write function of Fortran f90 in a separate file? - function

I want to write function in a separate file myfunction.f90 and how to modify test.f90 to call it
program test
implicit none
external myfunc
real :: x,myfunc
x = 5
write(*,*) myfunc(x)
end program test
function myfunc(x)
implicit none
real :: myfunc,x
myfunc = x**2
end function myfunc
I separate into 2 files test.f90
program test
implicit none
external myfunc
real :: x,myfunc
x = 5
write(*,*) myfunc(x)
end program test
and myfunc.f90
function myfunc(x)
implicit none
real :: myfunc,x
myfunc = x**2
end function myfunc
But it does not work

The canonical solution is to create a file with a module that includes all your functions after the contains keyword.
Then reference the module in your program with use mymodule and include both files to the compiler command.

Related

Fortran generic functions based on the return kind

I am trying to create a generic function in Fortran based on the value to be returned, that is, depending on if the output of the function is to be assigned to a single precision real or to a double precision real. The code is:
MODULE kk_M
USE ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: sp = REAL32
INTEGER, PARAMETER :: dp = REAL64
INTERFACE use_func
MODULE PROCEDURE use_sp_func
MODULE PROCEDURE use_dp_func
END INTERFACE use_func
INTERFACE use_sub
MODULE PROCEDURE use_sp_sub
MODULE PROCEDURE use_dp_sub
END INTERFACE use_sub
CONTAINS
FUNCTION use_sp_func() RESULT(res)
REAL(KIND=sp) :: res
res = 5._sp
END FUNCTION use_sp_func
FUNCTION use_dp_func() RESULT(res)
REAL(KIND=dp) :: res
res = 5._dp
END FUNCTION use_dp_func
SUBROUTINE use_sp_sub(res)
REAL(KIND=sp), INTENT(OUT) :: res
res = 5._sp
END SUBROUTINE use_sp_sub
SUBROUTINE use_dp_sub(res)
REAL(KIND=dp), INTENT(OUT) :: res
res = 5._dp
END SUBROUTINE use_dp_sub
END MODULE kk_M
PROGRAM kk
USE kk_M
IMPLICIT NONE
REAL(KIND=sp) :: num_sp
REAL(KIND=dp) :: num_dp
num_sp = use_func()
WRITE(*,*) num_sp
num_dp = use_func()
WRITE(*,*) num_dp
CALL use_sub(num_sp)
WRITE(*,*) num_sp
CALL use_sub(num_dp)
WRITE(*,*) num_dp
END PROGRAM kk
With the generic subroutines the code compiles and works, but when I add the generic functions it does not compile. I get the following error message with gfortran:
kk.f90:22:3:
FUNCTION use_sp_func() RESULT(res)
1
kk.f90:27:3:
FUNCTION use_dp_func() RESULT(res)
2
Error: Ambiguous interfaces in generic interface 'use_func' for ‘use_sp_func’ at (1) and ‘use_dp_func’ at (2)
kk.f90:46:7:
USE kk_M
1
Fatal Error: Can't open module file ‘kk_m.mod’ for reading at (1): No existe el archivo o el directorio
compilation terminated.
It looks like the compiler cannot distinguish between both functions based on the value to be returned. Is there some way to achieve this?
You cannot distinguish specific functions in a generic interface by their return value. There is no way how the compiler can see what return value type is to be used. A Fortran expression is always evaluated without the surrounding context. Fortran generic disambiguation is based by TKR (type, kind, rank) resolution only using the procedure arguments, not using the return value.
When you have
use_func()
there is no way for the compiler to know which of those two functions should be called. Even when it is used directly in an assignment
x = use_func()
it is evaluated separately. In general, function calls can appear in various complicated expressions. E.g. use_func(use_func()) + use_func(), which one would be which?
This is the reason why several intrinsic functions have another argument that specifies the return type. For example, the transfer() function has a second argument that specifies which type should be returned. Otherwise the compiler would not be able to find out.
Following the advice by Vladimir F, I had a look at the transfer intrisic function and added a mold parameter to my functions to set the return type.
If any input argument to the functions were real they could be used to set the return type as High Performace Mark stated, but since this is not my case I finally used the mold variable.
Now it compiles and work. The code is:
MODULE kk_M
USE ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: sp = REAL32
INTEGER, PARAMETER :: dp = REAL64
INTERFACE use_func
MODULE PROCEDURE use_sp_func
MODULE PROCEDURE use_dp_func
END INTERFACE use_func
INTERFACE use_sub
MODULE PROCEDURE use_sp_sub
MODULE PROCEDURE use_dp_sub
END INTERFACE use_sub
CONTAINS
FUNCTION use_sp_func(mold) RESULT(res)
REAL(KIND=sp),INTENT(IN) :: mold
REAL(KIND=sp) :: res
IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
res = 5._sp
END FUNCTION use_sp_func
FUNCTION use_dp_func(mold) RESULT(res)
REAL(KIND=dp),INTENT(IN) :: mold
REAL(KIND=dp) :: res
IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
res = 5._dp
END FUNCTION use_dp_func
SUBROUTINE use_sp_sub(res)
REAL(KIND=sp), INTENT(OUT) :: res
res = 5._sp
END SUBROUTINE use_sp_sub
SUBROUTINE use_dp_sub(res)
REAL(KIND=dp), INTENT(OUT) :: res
res = 5._dp
END SUBROUTINE use_dp_sub
END MODULE kk_M
PROGRAM kk
USE kk_M
IMPLICIT NONE
REAL(KIND=sp) :: num_sp
REAL(KIND=dp) :: num_dp
num_sp = use_func(1._sp)
WRITE(*,*) num_sp
num_dp = use_func(1._dp)
WRITE(*,*) num_dp
CALL use_sub(num_sp)
WRITE(*,*) num_sp
CALL use_sub(num_dp)
WRITE(*,*) num_dp
END PROGRAM kk

error when defining function inside another function in fortran

For some use I need to define a function inside another function inside a fortran module.
A sample code for easy comprehension is
module func
implicit none
contains
real function f(x,y)
real x,y,g
real function g(r)
real r
g=r
end function g
f=x*g(y)
end function f
end module func
use func
implicit none
write(*,*) f(1.0,1.0)
end
This is giving lots of errors in gfortran like unexpected data declaration, expected end function f, not g....etc.
What is the correct way of defining a function inside another function in fortran?
You use an internal subprogram, see below. Note internal subprograms themselves can not contain internal subprograms.
ian#eris:~/work/stack$ cat contained.f90
Module func
Implicit None
Contains
Real Function f(x,y)
! Interface explicit so don't need to declare g
Real x,y
f=x*g(y)
Contains
Real Function g(r)
Real r
g=r
End Function g
End Function f
End Module func
Program testit
Use func
Implicit None
Write(*,*) f(1.0,1.0)
End Program testit
ian#eris:~/work/stack$ gfortran-8 -std=f2008 -Wall -Wextra -fcheck=all -O -g contained.f90
ian#eris:~/work/stack$ ./a.out
1.00000000
ian#eris:~/work/stack$

Character elemental function. Give a parameter as char-length to interface?

The question is why i get an error saying the integer charlen is a real when i pass it as the length definition of a character elemental function. To be more specific, the folowing MWE works:
program chararr
implicit none
!!
integer,parameter :: charlen = 20
!!
interface
character(len=20) elemental function adjR(a)
character(len=*),intent(in) :: a
end function
end interface
!!
character(charlen) :: test(3), testR(3)
test = ["hej", "hoj", "haj"]
testR = adjR(test)
print*, test
print*, testR
end program
character(20) elemental function adjR(a)
character(len=*),intent(in) :: a
adjR = adjustr(a)
end function
but the line integer,parameter :: charlen = 20 does nothing. When i change the function and interface definitions like this
character(len=charlen) elemental function adjR(a)
i get the following error:
charmin.f90:7:14:
character(len=charlen) elemental function adjR(a)
1
Error: Expression at (1) must be of INTEGER type, found REAL
UPDATE
The solution of Alexander is in code:
charmin.f90:
program chararr
use char_mod, only: charlen, adjR
implicit none
!!
!interface
!character(30) elemental function adjR(a)
!character(len=*),intent(in) :: a
!end function
!end interface
!!!
character(charlen) :: test(3), testR(3)
test = ["hej", "hoj", "haj"]
testR = adjR(test)
print*, test
print*, testR
print*, charlen !!! it is here
end program
char_mod.f90:
module char_mod
implicit none
integer,parameter :: charlen = 30
private
public charlen, adjR
contains
character(charlen) elemental function adjR(a)
implicit none
character(len=*),intent(in) :: a
adjR = adjustr(a)
end function
end module
To compile:
gfortran -c char_mod.f90
gfortran charmin.f90 char_mod.f90 -o program
charlen is defined in the scope of the program, but the function adjR is outside that scope. Consequently, charlen is not accessible, and since the function does not have implicit none defined, it is interpreted as a real variable.
One solution to this would be to put adjR in a module, and make charlen a module variable.

The invoked function has its own inherited variable in the OpenMP parallel region

The purpose of the example below is to parallelize a do loop over a subroutine named "sub1" that invokes a function in which a simple addition operation is executed.
The problem that troubles me is that, in my mathematical model, the invoked function has two input arguments, (a,e), but for some reason in my code, I am restricted to pass a single-argument function to the subroutine "sub1." The solution I figured out is to set the second variable "e" to be inherited by the invoked function from the module it resides. The outcome looks good to me.
I am wondering whether using heritage to pass more than one arguments---identically defined in the module where the invoked function resides---to the invoked function in the parallel region will lead to any racing problem.
Thanks.
Lee
---- There are two files in this example: main.f90 and model.f90.
MAIN.f90
program main
! The definition of sub1 is:
! taking function_1,input_2,input_3 as inputs and
! returning output_4 as output
use omp_lib
use model
implicit none
integer :: j
real :: m(1000),k(1000)
m=[(real(j),j=1,1000)]
!$omp parallel do private(j) shared(m,k)
do j=1,1000
call sub1(fun1,m(j),2.,k(j))
enddo
!$omp end parallel do
end program main
MODEL.F90
module model
implicit none
real :: e
contains
subroutine sub1(func,a,c,d)
implicit none
real, intent(in) :: a,c
real, intent(out) :: d
interface
real function func(a)
implicit none
real :: a
end function func
end interface
e=c
d=func(a)
end subroutine sub1
real function fun1(a)
implicit none
real :: a
fun1=a**e
end function fun1
end module model
Yes, more threads will try to write to the variable e in this line
e=c
and that is a race condition. You can make it threadprivate. That way every thread will have its private copy that will persist during the calls.
In Fortran 2008 you could also do something along the lines of the program below, but the principle is the same.
module model
implicit none
real :: e
contains
subroutine sub2(func,a,d)
implicit none
real, intent(in) :: a
real, intent(out) :: d
interface
real function func(a)
implicit none
real :: a
end function func
end interface
d=func(a)
end subroutine
end module model
program main
! The definition of sub1 is:
! taking function_1,input_2,input_3 as inputs and
! returning output_4 as output
use omp_lib
use model
implicit none
integer :: j
real :: c
real :: m(1000),k(1000)
m=[(real(j),j=1,1000)]
!$omp parallel do private(j,c) shared(m,k)
do j=1,1000
c = i
call sub2(fun1,m(j),k(j))
enddo
!$omp end parallel do
contains
real function fun1(a)
implicit none
real :: a
fun1=a**c
end function fun1
end program main

Pointer to a function inside a derived type on a module in fortran

I guess I could easily use some help here, since I'm messing around with some fortran 2003 but can't seem to understand how to do things really.
The fact is that I need to write a fortran code that declares, inside a module, a new data type
that has as one of its members a pointer to a real function. Something like
module new_mod
type my_type
real*8 :: a, b
(here something that declares a real*8 function), pointer :: ptr
end type my_type
end module_new
module funcs
real*8 function function1(x)
real*8 :: x
function1 = x*x
end function function1
real*8 function function2(x)
real*8 :: x
function2 = x*x
end function function2
end module funcs
then in the main program I would like to have something like
program my_prog
use module_new
use module_funcs
implicit none
real*8 :: y, z
type(my_type) :: atom
...
atom%ptr => function1
y = atom%ptr(x)
...
atom%ptr => function2
z = atom%ptr(x)
end program my_prog
while
so the main idea is that module_new contains a type that has a pointer to a real
function. This pointer in th eobjects of the new type I must be able to point to different functions in the main program.
I have seen one can do similar things with abstract interfaces and such, but honestly, I'm in a mess here. If someone could help, I'll appreciate that.
Cheers...
Well, that is not really the type of question you would send to stackoverflow, but actually your code needs only a "slight improvement" (by appropriate definition of slight) to work:
module accuracy
implicit none
integer, parameter :: dp = kind(1.0d0)
end module accuracy
module typedef
use accuracy
implicit none
type :: mytype
real(dp) :: aa, bb
procedure(myinterface), pointer, nopass :: myfunc
end type mytype
abstract interface
function myinterface(xx)
import :: dp
real(dp), intent(in) :: xx
real(dp) :: myinterface
end function myinterface
end interface
end module typedef
module funcs
use accuracy
implicit none
contains
function func1(xx)
real(dp), intent(in) :: xx
real(dp) :: func1
func1 = xx
end function func1
function func2(xx)
real(dp), intent(in) :: xx
real(dp) :: func2
func2 = 2.0_dp * xx
end function func2
end module funcs
program test
use accuracy
use typedef
use funcs
implicit none
real(dp) :: xx
type(mytype) :: atom
xx = 12.0_dp
atom%myfunc => func1
print *, atom%myfunc(xx)
atom%myfunc => func2
print *, atom%myfunc(xx)
end program test
There are several things to be worth to mentioned:
You should use one global parameter for your accuracy (see module accuracy) and forget about real*8.
Your procedure pointer in your derived type needs an interface, which is provided within the following abstract interface block (see 'abstract interfaces' in a good F2003 book).
You need the nopass option for the procedure pointer in the derived type as otherwise Fortran will assume that the first parameter passed to the function/subroutine is the derived type itself (see 'type bound procedures' in a good F2003 book).
Finally, although rather obvious: You should definitely read a book about the Fortran 2003 features if you are serious about using them in a production code.