Fortran: Implement a subroutine that accepts another subroutine as an argument in Fortran 90/95

253 Views Asked by At

I would like to write a Fortran subroutine that accepts the name of another subroutine as an argument --- imagine that the first subroutine is a PDE solver while the second provides the right-hand side of the PDE. Note that the second subroutine may be implemented by others, and hence we may not know anything about it except for its signature.

This is possible using abstract interfaces and a procedure statements. See, for example, https://github.com/jacobwilliams/PowellOpt/blob/master/src/newuoa.f90

It is of course also doable using external functions: http://malayamaarutham.blogspot.com/2006/02/passing-function-names-as-arguments-in.html

However, abstract interfaces and procedure statements are available only after Fortran 2003, while external functions are not desirable. Here comes my first question:

Is it possible to pass a subroutine name as an argument in Fortran 90/95 without using abstract interfaces and procedure statements or external functions?

The answer seemed negative to me at the beginning, because I saw this discussion: http://computer-programming-forum.com/49-fortran/dba58f497a8dc996.htm

Fortunately, after more study, I found it possible via the normal interface (not the abstract one) according to sources like Fortran | Passing functions as arguments in other functions , How to pass subroutine names as arguments in Fortran? , https://www.tek-tips.com/viewthread.cfm?qid=1572869 .

I implemented the following piece of code as a minimal working example. My second question is:

Is the following piece of code Fortran 90/95 compliant?

I tried compiling the code using gfortran, ifort, and g95. The first two compilers were happy, but g95 raised a warning that

use fun_mod, only : fun
                    1
Warning (102): MODULE PROCEDURE 'fun' USEd at (1) is not referenced

when I executed

g95 -Wall -Wextra -std=f95 -pedantic main.f90

The resultant executable worked without any problem, but why this warning? Is this a bug of g95? If not, how to get rid of this warning? Any other comments/criticism on the code will also be highly appreciated.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module proc_mod 
! PROC_MOD provides a subroutine PROC(X, Y, F) that invokes a subroutine
! F at (X, Y) and then increment Y by 1.

implicit none
private 
public :: proc


contains


subroutine proc(x, y, f)

implicit none

real, intent(in) :: x(:)
real, intent(out) :: y

interface
    subroutine f(x, y)
    real, intent(in) :: x(:)
    real, intent(out) :: y
    end subroutine f
end interface

call f(x, y)
y = y + 1.0

end subroutine proc 


end module proc_mod
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module fun_mod
! FUN_MOD provides a subroutine FUN(X, Y) that sets Y = SUM(X**2).
! In practice, this module is provided by OTHERS, and we do not
! know how it is implemented except for the signature of FUN.

implicit none
private 
public :: fun 


contains 


subroutine fun(x, y)

implicit none
real, intent(in) :: x(:)
real, intent(out)  :: y 

y = sum(x**2)

end subroutine fun


end module fun_mod
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program main 
! MAIN tests PROC(X, Y, FUN) with PROC from PROC_MOD and FUN from FUN_MOD.

use proc_mod, only : proc
use fun_mod, only : fun
implicit none

real :: x(3), y

call random_number(x)
print *, x

call proc(x, y, fun)
print *, y

print *, sum(x**2) + 1.0

end program main 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Note that, in this code, we need to write an interface block for FUN in every subroutine that receives FUN as an argument. It would be tedious if I had many such subroutines. This motivates my third question:

Is it possible to wrap the interface of FUN in a module and dispense the interface block by using the module? (I tried but did not succeed.)

Thank you very much!

Edit: As pointed out by @Ian Bush and @francescalus, maybe I should accept using abstract interfaces and procedure statements, checking whether the users' compilers implement such a feature of F2003. So here comes the 4th question:

What is the earliest version of commonly used Fortran compilers (gfortran, ifort, nagfor, pgfortran ...) that implements the abstract interface and the procedure statement?

I know that I should check the documentation myself --- I will. I put this question here just in case someone knows the answer. Later I will edit the question to include the answer in case someone else is looking for the same thing. Thanks.

Answer to the fourth question:

0

There are 0 best solutions below