Calling a subroutine multiple times with different function as argument each time - fortran

I'm enough of a novice to not know the terminology, so I can't search the Web for the answer to this.
More than once, in programming, I've wanted to do something like this.
A and B are subroutines, c and d are functions. A and B each call a function multiple times inside them.
call A(c(x))
call A(d(x))
call B(c(x))
call B(d(x))
This structure doesn't work. I'm told that Fortran doesn't support aliasing of functions, at least in this context. (Most search results involving "aliasing" refer to aliasing variables rather than functions, which is why I haven't found an answer.)
So what structure can I use to do this without having to write multiple versions of A and B?

Not totally sure I understand what you want, but is it something like the following?
Program f
Implicit None
Interface
Integer Function c( x )
Implicit None
Integer, Intent( In ) :: x
End Function c
Integer Function d( x )
Implicit None
Integer, Intent( In ) :: x
End Function d
End Interface
Call a( 3, c )
Call a( 4, d )
Call b( 5, c )
Call b( 6, d )
Contains
Subroutine a( x, func )
Integer, Intent( In ) :: x
Interface
Integer Function func( x )
Implicit None
Integer, Intent( In ) :: x
End Function func
End Interface
Write( *, * ) 'In a. Func = ', func( x )
End Subroutine a
Subroutine b( x, func )
Integer, Intent( In ) :: x
Interface
Integer Function func( x )
Implicit None
Integer, Intent( In ) :: x
End Function func
End Interface
Write( *, * ) 'In b. Func = ', func( x )
End Subroutine b
End Program f
Integer Function c( x )
Implicit None
Integer, Intent( In ) :: x
c = 2 * x
End Function c
Integer Function d( x )
Implicit None
Integer, Intent( In ) :: x
d = 10 * x
End Function d
Wot now? gfortran -std=f95 f.f90
Wot now? ./a.out
In a. Func = 6
In a. Func = 40
In b. Func = 10
In b. Func = 60
Wot now?
An alternative is procedure pointers, but you'll need a f2003 compiler for that and those are not so common yet - the above is fine back to f90 and even earlier than that External will do what you want, but has less error checking capabilities

call A(c(x)) looks like evaluate c(x) and pass that to subroutine A, as IanH says in his comment.
If you want to pass a function "C" that takes an argument of type such as X to subroutine A, there are several ways to do that.
As already mentioned, procedure pointers are a new way. While extremely few compilers exist that support all of the Fortran 2003 standard, this portion is widely supported.
Here is an example adapted from Function pointer arrays in Fortran
module ProcsMod
implicit none
contains
function f1 (x)
real :: f1
real, intent (in) :: x
f1 = 2.0 * x
return
end function f1
function f2 (x)
real :: f2
real, intent (in) :: x
f2 = 3.0 * x**2
return
end function f2
subroutine fancy (func, x, answer)
real, intent (in) :: x
real, intent (out) :: answer
interface AFunc
function func (y)
real :: func
real, intent (in) ::y
end function func
end interface AFunc
answer = func (x)
end subroutine fancy
end module ProcsMod
program test_proc_ptr
use ProcsMod
implicit none
interface
function func (z)
real :: func
real, intent (in) :: z
end function func
end interface
procedure (func), pointer :: f_ptr => null ()
real :: answer
f_ptr => f1
call fancy (f_ptr, 2.0, answer)
write (*, *) answer
f_ptr => f2
call fancy (f_ptr, 2.0, answer)
write (*, *) answer
stop
end program test_proc_ptr
The calls "call fancy (f_ptr, 2.0, answer)" look the same, but by changing the function that the function pointer f_ptr points to, a different function is passed to the subroutine fancy.
This compiles with both gfortran (versions 4.4 to 4.7) and ifort.

I think M.S.B.'s answer describes what you mean by aliasing of functions; the Fortran terminology is "procedure pointers". As an alternative to this and Ian's answer, you can also use procedure dummy arguments (which are not necessarily pointers). Note that any procedure declaration is only supported since F2003, but gfortran 4.7 and ifort 13 both support this. It can be done with or without an (abstract) interface block:
module dummy_procedure
implicit none
abstract interface
real function myfunc(x)
real, intent(in) :: x
end function
end interface
contains
subroutine a(func)
! Using the interface block:
procedure(myfunc) :: func
print*, 'a:', func(.5)
end subroutine
subroutine b(func)
! Using the explicit interface of a known procedure:
procedure(f1) :: func
print*, 'b:', func(.5)
end subroutine
real function f1(x)
real, intent(in) :: x
f1 = 2.0 * x
end function
real function f2(x)
real, intent(in) :: x
f2 = 3.0 * x**2
end function
end module
Now you can pass f1 and f2 directly into a and b, and the output is as expected:
program main
use dummy_procedure
call a(f1) ! a: 1.0
call a(f2) ! a: 0.75
call b(f1) ! b: 1.0
call b(f2) ! b: 0.75
end program

If I understand what you're trying to do:
1) Define your functions in a module.
2) Use the module.
3) Supply the function and the input data to the subroutine as separate arguments.
Here's a code that worked for me:
module iterfuncs
contains
! two example functions:
function approach_golden_ratio(a) result(agr)
agr=1./a+1.
end function approach_golden_ratio
function approach_other_ratio(a) result(aor)
aor=1./(a-1)
end function approach_other_ratio
end module
program use_some_functions
use iterfuncs
real :: final_res
final_res=2.3
! call subroutine with 1st function
call iterate(final_res,approach_golden_ratio)
print *,final_res
final_res=2.3
! call subroutine with 2nd function
call iterate(final_res,approach_other_ratio)
print *,final_res
end program
subroutine iterate(res,func)
use iterfuncs
do n=1,100
res=func(res)
enddo
return
end subroutine

Related

Passing and using an optional mask within subroutine

I pass an optional mask to a subroutine. Within this routine I then have many statements of the kind
...
if (present(Mask)) then
where(Mask)
y(:) = A(:)*B(:)
end where
else
y(:) = A(:)*B(:)
end if
...
This is very ugly in regards of code duplication. Are there any advices to do this in a better way? I have many statements like this in my code and I need to perform the operations on whole arrays.
Edit:
At least a part of the problem can be solved through elemental functions. Because I have the same operations on the right side I can write
...
if (present(Mask)) then
where(Mask)
y(:) = multiply(A(:),B(:))
end where
else
y(:) = multiply(A(:),B(:))
end if
...
elemental real function multiply(a,b)
real, intent(in) :: a,b
multiply = a*b
end function
This way, I have at least a single place for the operations.
There is the option (pun intended) to no use optional arguments, and instead, write a generic interface. For example, instead of writing
subroutine bar(arg0, opt)
integer, intent(inout) :: arg0
integer, intent(in), optional :: opt
arg0 = int(4 * atan(1.))
if (present(opt)) arg0 = arg0 + opt
module foo
You can do
interface bar
module procedure bar0
module procedure bar1
end interface bar
contains
subroutine bar0(arg0)
integer, intent(inout) :: arg0
arg0 = int(4 * atan(1.))
end subroutine bar0
subroutine bar1(arg0, opt)
integer, intent(inout) :: arg0
integer, intent(in) :: opt
arg0 = arg0 + opt
end subroutine bar1
end module foo
program bah
use foo
integer :: a0 = 1, a1 = 42
call bar(a0)
print *, a0
call bar(a0, a1)
print *, a0
end program bah
One advantage that you may gain from this approach is that bar0
and bar1 may allow a compiler to do a better job of optimizing
the code. The if (present(opt)) construct may get in the way.

How to make a generic procedure pointer in Fortran?

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

Wrong result when using a global variable in Fortran

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

Keyword OPTIONAL in TYPE in Fortran does not work

I try the following codes, and find the OPTIONAL keyword does not work. The compile is ok, but the runtime error will prompt.
I know usually the INTERFACE should be used in the module to provide enough information for the routines. I also try that, but failed to finish the compile no matter where I put the INTERFACE.
I have read some codes which use OPTIONAL in the TYPE declaration. https://www.pgroup.com/lit/articles/insider/v3n1a3.htm
Now I am using intel visual fortran, so is there any difference?
module testA_m
implicit none
type :: onion_c
contains
procedure :: testA
end type
contains
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
write(*,*) a,b
end subroutine
end module
program main
call testIt()
end program
subroutine testIt()
use testA_m
implicit none
type(onion_c) :: onion
real*8 :: c1
real*8 :: c2
c1 = 1.0d0
c2 = 2.0d0
call onion.testA(c1)
end subroutine
Well, you are trying to print b, which is not passed to the subroutine. Hence the access violation.
You should check for b first:
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
if ( present(b) ) then
write(*,*) a,b
else
write(*,*) a
endif
end subroutine
Maybe I need another variable for the real operation. Like the following.
I am still looking forward the better solution to use b directly.
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
real*8 :: bUsed
if ( present(b) ) then
bUsed = b
write(*,*) a,bUsed
else
bUsed = 2.00d0
write(*,*) a,bUsed
endif
end subroutine
Because Fortran does not support a program like
subroutine testA( this, a, b=10.0d0 )
I usually define a macro like the following in a common header file
#define _optval_(x,xopt,default) x = default; if (present(xopt)) x = xopt
and then use it at the top of a subroutine like
subroutine testA(this, a,b_)
class(onion_c) :: this
real*8 :: a
real*8, optional :: b_
real*8 b
_optval_( b, b_, 10.0d0 ) !! use only b from here on
Although this is not essentially different from writing several IF constructs, I feel it is a bit more convenient (at least for simple variables) because no need to worry about whether b is optional or not in the subsequent code. (But frankly, I hope Fortran2020 or so will support a syntax like the first example...)

Initializing constant with variable's value

program main
real, parameter :: a = 1
!real :: a
!a=1
res = func(a)
write(*,*) res
end program main
function func(a)
real, parameter :: b=a+1 !(*)
func = b
return
end function func
My compiler complains at the line marked (*). Is there a way to set the value of a constant with a value coming outside that function?
You can't declare "b" as a parameter since its value is not constant at compile time, since it depends on the function argument.
It is a good idea to use "implicit none" so that you are sure to declare all variables. Also to place your procedures into a module and "use" that module so that the interface is known to the caller. As in:
module my_funcs
implicit none
contains
function func(a)
real :: func
real, intent (in) :: a
real :: b
b = a + 1
func = b
return
end function func
end module my_funcs
program main
use my_funcs
implicit none
real, parameter :: a = 1
real :: res
res = func(a)
write(*,*) res
end program main
#M. S. B.'s answer is fine if run-time initialization is acceptable to you. If you really do want a Fortran parameter, which is set at compile time, then you can do it like this:
program main
implicit none
real, parameter :: a = 1.0
real :: res
res = func()
write(*,*) res
contains
function func()
real, parameter :: b = a + 1.0
real :: func
func = b
end function func
end program main
I suspect part of the confusion is due to differences in language. Often "parameter" is used to mean an argument of a function, but in Fortran it is never used that way. Instead it means something similar to const in C/C++. So, it is not clear to me from your question whether you really want a Fortran parameter or not.
In my example above, the parameter a is known inside func via host association, which is Fortran lingo for nested scopes. You can also do it with modules, via use association, but it is a bit more verbose:
module mypars
implicit none
real, parameter :: a = 1.0
end module mypars
module myfuncs
implicit none
contains
function func()
use mypars, only: a
real, parameter :: b = a + 1.0
real :: func
func = b
end function func
end module myfuncs
program main
use myfuncs, only: func
implicit none
real :: res
res = func()
print *, res
end program main