如何将子例程的输出之一用作函数?

How to use one of the outputs of a subroutine as a function?

我在 Fortran 中工作,我试图将子例程的输出之一用作函数并对其进行操作,但我不知道如何正确地进行操作。这是我正在尝试做的测试程序

module funciones
 use, intrinsic :: iso_fortran_env, only: dp => real64
 implicit none

type ptr_wrapper
  procedure(f), nopass, pointer :: func
end type ptr_wrapper

abstract interface
function f(x1,x2)
   import
   real(dp), intent(in) :: x1,x2
   real(dp) :: f
 end function f
end interface

abstract interface
 subroutine g(x,y,f1,f2)
import
real(dp), intent(in) :: x,y
real(dp), intent(out) :: f1,f2
end subroutine g
end interface

contains 
 subroutine test_func(x,y,f1,f2)
 real(dp), intent(in) :: x,y
 real(dp), intent(out) :: f1,f2

 f1 = x*y
 f2 = 2d0*x+5d0*y

 end subroutine test_func

 function Derivate (x,y,fx) result (d)
    implicit none
    real(dp), intent(in) :: x,y
    procedure(f), pointer :: fx
    real(dp) :: d

    real(dp) :: h = 1.0E-6

    d = (1.0*fx(x-2*h,y) - 8.0*fx(x-h,y) + 8.0*fx(x+h,y) -   1.0*fx(x+2*h,y))/(12.0*h)
end function Derivate


function separation1(x,y,F_in) result(DF_out1)
    implicit none
    real(dp), intent(in) :: x,y
    procedure(g) :: F_in
    real(dp) :: F_out1, F_out2
    real(dp) :: DF_out1
    procedure (f), pointer:: F1_ptr
    Call F_in (x,y,F_out1,F_out2)
    F1_ptr => F_out1
    DF_out1 = Derivate(x,y,F1_ptr)
end function separation1

function separation2(x,y,F_in) result(F_out2)
    implicit none
    real(dp), intent(in) :: x,y
    procedure(g) :: F_in
    real(dp) :: F_out1, F_out2
    Call F_in (x,y,F_out1,F_out2)
end function separation2


 end module funciones

program testsubroutines
 use, intrinsic :: iso_fortran_env, only: dp => real64
 use funciones
 implicit none


 print*, separation1(1d0,3d0,test_func)
 print*, separation2(1d0,3d0,test_func)



end program testsubroutines

所以基本上这个程序创建测试功能(使用子例程)然后分离出来。函数 separate2 工作正常,所以我决定向前迈出一步,在 separate1 中实现派生它的函数。但是我不知道如何将指针分配给 out 并且我总是在该行中遇到错误。

我也试过创建两个指针

F1_ptr,F2_ptr

并将它们分配为

(F1_ptr,F2_ptr)=>Call F_in(x,y,F_out1,F_out2)

但我明白了

Error : Unclassifiable assignment at (1).

如果我赋值为

F1_ptr => F_out1

我收到错误消息

Error: Invalid procedure pointer assignment at (1)

或者如果我这样做

F1_ptr %func => Call F_in (x,y,F_out1,F_out2)
             1
Error: Invalid character in name at (1)

DF_out1 = Derivate(x,y,F1_ptr)
                     1
Error: Type mismatch in argument ‘fx’ at (1); passed TYPE(ptr_wrapper) to REAL(8)

我也尝试了这两个变化

...
abstract interface
subroutine g(x,y,f1,f2)
import
real(dp), intent(in) :: x,y
procedure(f),pointer :: f1,f2
end subroutine g
end interface

contains 
subroutine test_func(x,y,f1,f2)
real(dp), intent(in) :: x,y
type (ptr_wrapper) :: f1,f2
f1%func => x*y
f2%func => 2d0*x+5d0*y

...

但我得到

 f1%func => x*y
        1
 Error: Invalid procedure pointer assignment at (1)

和 f2

的相同错误消息

那么,我该怎么做呢?

子例程 test_func 有两个伪参数,让子例程报告两个 ,这些值是子例程内部某些计算的结果。

在 Fortran 中,值不是函数

(这种区别在某些其他语言中是模糊的或消除的,但在 Fortran 中不是。)

在 Fortran 中,值是调用函数时可能产生的结果,但调用函数与函数本身之间存在差异。

我不清楚这个问题背后的意图,但是如果你想公开子程序 test_func 中的计算(顺便说一句 - 将 "func" 放在一个名称中子例程相当混乱)作为一个函数,那么您需要编写一个调用 test_func 的函数,将感兴趣的输出参数作为函数结果传回。这样的函数很简单,可以是这样的:

function get_f1_from_test_func(x, y) result(f1)
  real(dp), intent(in) :: x
  real(dp), intent(in) :: y
  real(dp) :: f1
  real(dp) :: ignored
  call test_func(x, y, f1, ignored)
end function get_f1_from_test_func

该函数 returns test_funcf1 虚拟参数的值。如果您想要 f2 参数,请编写另一个函数。

function get_f2_from_test_func(x, y) result(f2)
  real(dp), intent(in) :: x
  real(dp), intent(in) :: y
  real(dp) :: f2
  real(dp) :: ignored
  call test_func(x, y, ignored, f2)
end function get_f2_from_test_func

以上两个函数与Derivate的fx伪参数要求的函数接口一致

如上述包装函数中局部变量的名称所示,当调用包装函数时,test_func 的输出伪参数之一的结果将被丢弃。这在计算上不太可能有效,但这种情况是在 test_func.

中将两个计算捆绑在一起的结果