我想编写一个 Fortran 子程序,它接受另一个子程序的名称作为参数——假设第一个子程序是 PDE 求解器,而第二个子程序提供 PDE 的右侧。请注意,第二个子程序可能由其他人实现,因此我们可能对它一无所知,除了它的签名。
这可以使用抽象接口和过程语句来实现。例如,参见 https://github.com/jacobwilliams/PowellOpt/blob/master/src/newuoa.f90
当然也可以使用外部函数: http: //malayamaarutham.blogspot.com/2006/02/passing-function-names-as-arguments-in.html
但是,抽象接口和过程语句仅在 Fortran 2003 之后可用,而外部函数则不可取。这是我的第一个问题:
是否可以在不使用抽象接口和过程语句或外部函数的情况下在 Fortran 90/95 中将子例程名称作为参数传递?
一开始我的答案似乎是否定的,因为我看到了这个讨论: http ://computer-programming-forum.com/49-fortran/dba58f497a8dc996.htm
幸运的是,经过更多研究,根据 Fortran |等来源,我发现可以通过普通接口(不是抽象接口)实现。在其他函数中将函数作为参数传递, 如何在 Fortran 中将子例程名称作为参数传递?, https://www.tek-tips.com/viewthread.cfm?qid=1572869。
我实现了以下代码作为最小的工作示例。我的第二个问题是:
以下代码符合 Fortran 90/95 标准吗?
我尝试使用 gfortran、ifort 和 g95 编译代码。前两个编译器很高兴,但是 g95 提出了一个警告:
use fun_mod, only : fun
1
Warning (102): MODULE PROCEDURE 'fun' USEd at (1) is not referenced
当我执行
g95 -Wall -Wextra -std=f95 -pedantic main.f90
生成的可执行文件没有任何问题,但为什么会出现这个警告?这是g95的bug吗?如果没有,如何摆脱这个警告?对代码的任何其他评论/批评也将受到高度赞赏。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
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
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
请注意,在这段代码中,我们需要在每个接收 FUN 作为参数的子程序中为 FUN 编写一个接口块。如果我有很多这样的子例程,那将是乏味的。这激发了我的第三个问题:
是否可以将 FUN 的接口封装在一个模块中,并使用该模块分配接口块?(我试过但没有成功。)
非常感谢!
编辑:正如@Ian Bush 和@francescalus 所指出的,也许我应该接受使用抽象接口和过程语句,检查用户的编译器是否实现了F2003 的这种功能。那么第四个问题来了:
实现抽象接口和过程语句的常用 Fortran 编译器(gfortran、ifort、nagfor、pgfortran ...)的最早版本是什么?
我知道我应该自己检查文档——我会的。我把这个问题放在这里,以防有人知道答案。稍后我将编辑问题以包含答案,以防其他人正在寻找相同的东西。谢谢。
回答第四个问题:
- gfortran:4.3(根据https://gcc.gnu.org/wiki/GFortran/News#GCC4.3),2008 年发布
- nagfor:5.1(根据http://geco.mines.edu/software/nagfor/nag_f2003.html#AUTOTOC_9_1),2008 年发布
- 适用于 Linux 或 AIX 的 IBM XL Fortran:不迟于 12.1(根据http://publibfp.dhe.ibm.com/epubs/pdf/c2385550.pdf和https://www.ibm.com/support/pages/sites /default/files/support/swg/swgdocs.nsf/0/5f70ca824c75701b852574720069a576/%24FILE/compiler.pdf ),2008 年发布
- ifort :11.0(根据https://jp.xlsoft.com/documents/intel/compiler/11/Release_Notes_f_osx.pdf),2009年发布
- pgfortran:10.8(根据https://www.pgroup.com/support/new_rel_2010.htm#new),2010 年发布
- absoft Fortran:14.0(根据https://www.absoft.com/wp-content/uploads/2015/08/ProFortran2014WindowsReleaseNotes.pdf和http://www.gmsl.it/wp-content/uploads/2014/09 /Fortran_Reference.pdf ),2014 年发布