2014-11-22 62 views
2

我正在尝试编写一个用于最小化的通用子例程。因为我想有一个通用的子程序,所以目标函数可以有不同的参数,不仅在名称中,而且在维度中也是如此。所以我需要一种方法来传递参数结构(我使用的是单词结构,因为我的想法是使用类似于Matlab中的结构类型变量)。 我设法使用派生的数据类型,它工作得很好,但是当我在同一个程序中有两个不同的目标函数时会出现问题。这是一个示例代码:Fortran:将任意“结构”传递给模块子例程

在主程序main.f90时:

MODULE MYPAR 
    IMPLICIT NONE 
    TYPE PARPASS1 !! Parameter passing structure 1 
    INTEGER  :: a 
    REAL   :: X(2,2) 
    END TYPE PARPASS1 

    TYPE PARPASS2 !! Parameter passing structure 2 
    REAL   :: b 
    REAL   :: Y(3) 
    END TYPE PARPASS2 
END MODULE MYPAR 

PROGRAM MAIN 

    USE MYPAR 
    USE MYLIB 
    IMPLICIT NONE 

    INTEGER  :: am 
    REAL   :: bm,Xm(2,2),Ym(3),sol1,sol2 
    TYPE(PARPASS1) :: PARAM1 
    TYPE(PARPASS2) :: PARAM2 

    am = 1 
    bm = 3.5 
    Xm(1,:) = [1.0, 2.0] 
    Xm(2,:) = [0.5, 2.5] 
    Ym(1:3) = [0.25,0.50,0.75] 

    PARAM1%a = am 
    PARAM1%X = Xm 
    PARAM2%b = bm 
    PARAM2%Y = Ym 

    CALL MYSUB(sol1,OBJ1,PARAM1) 
    CALL MYSUB(sol2,OBJ2,PARAM2) 
    PRINT *,sol1 
    PRINT *,sol2 

CONTAINS 

    SUBROUTINE OBJ1(sumval,PARAM) 
    REAL,INTENT(OUT)   :: sumval 
    TYPE(PARPASS1),INTENT(IN) :: PARAM 
    INTEGER     :: a 
    REAL,ALLOCATABLE   :: X(:,:) 
    a = PARAM%a 
    X = PARAM%X 
    sumval = a+X(1,1)+X(2,2) 
    END SUBROUTINE OBJ1 

    SUBROUTINE OBJ2(divval,PARAM) 
    REAL,INTENT(OUT)   :: divval 
    TYPE(PARPASS2),INTENT(IN) :: PARAM 
    REAL      :: b 
    REAL,ALLOCATABLE   :: Y(:) 
    b = PARAM%b 
    Y = PARAM%Y 
    divval = b/(Y(1)+Y(2)) 
    END SUBROUTINE OBJ2 

END PROGRAM MAIN 

和被叫mylib.90

MODULE MYLIB 

    USE MYPAR 
    IMPLICIT NONE 

CONTAINS 

    SUBROUTINE MYSUB(sol,FN,PARAM) 
    REAL,INTENT(OUT)   :: sol 
    TYPE(PARPASS1), INTENT(IN) :: PARAM 
    CALL FN(sol,PARAM) 
    sol = 2*sol 
    END SUBROUTINE MYSUB 

END MODULE MYLIB 

显然模块,如果我评论的线条与CALL MYSUB(sol2,OBJ2,PARAM2)PRINT *,sol2 ,我的代码运行顺利。这是我以前有两个“目标函数”,但现在当我有它们时,它不起作用,因为MYSUB中的派生类型变量PARPASS1不能是任意的。

任何想法?

回答

2

你可以使用一个接口和重载子程序MYSUB:

​​

然后,你可以通过使用MYSUB调用它,它会根据PARAM

类型

编辑区分功能:好吧,这个怎么样:

MODULE MYPAR 
    IMPLICIT NONE 

    type, abstract :: PARPASS 
    contains 
    procedure(func), deferred :: OBJ 
    end type PARPASS 

    TYPE, extends(PARPASS) :: PARPASS1 !! Parameter passing structure 1 
    INTEGER  :: a 
    REAL   :: X(2,2) 
    contains 
    procedure :: OBJ => OBJ1 
    END TYPE PARPASS1 

    TYPE, extends(PARPASS) :: PARPASS2 !! Parameter passing structure 2 
    REAL   :: b 
    REAL   :: Y(3) 
    contains 
    procedure :: OBJ => OBJ2 
    END TYPE PARPASS2 

    abstract interface 
    subroutine func(this, val) !Interface for the subroutine you want to implement 
     import 
     class(PARPASS), intent(in) :: this 
     real, intent(out) :: val 
    end subroutine func 
    end interface 

contains 

    subroutine OBJ1(this, val) 
    class(PARPASS1),INTENT(IN) :: this 
    real, intent(out)   :: val 
    INTEGER     :: a 
    REAL,ALLOCATABLE   :: X(:,:) 
    a = this%a 
    X = this%X 
    val = a+X(1,1)+X(2,2) 
    END subroutine OBJ1 

    subroutine OBJ2(this, val) 
    class(PARPASS2),INTENT(IN) :: this 
    real, intent(out)   :: val 
    REAL      :: b 
    REAL,ALLOCATABLE   :: Y(:) 
    b = this%b 
    Y = this%Y 
    val = b/(Y(1)+Y(2)) 

    END subroutine OBJ2 

END MODULE MYPAR 


MODULE MYLIB 

    USE MYPAR 
    IMPLICIT NONE 

CONTAINS 

    SUBROUTINE MYSUB(sol, param) 
    REAL,INTENT(OUT)   :: sol 
    class(PARPASS), INTENT(IN) :: PARAM 
    call param%obj(sol) 
    sol = 2*sol 
    END SUBROUTINE MYSUB 

END MODULE MYLIB 

PROGRAM MAIN 

    USE MYPAR 
    USE MYLIB 
    IMPLICIT NONE 

    INTEGER  :: am 
    REAL   :: bm,Xm(2,2),Ym(3),sol1,sol2 
    TYPE(PARPASS1) :: PARAM1 
    TYPE(PARPASS2) :: PARAM2 

    am = 1 
    bm = 3.5 
    Xm(1,:) = [1.0, 2.0] 
    Xm(2,:) = [0.5, 2.5] 
    Ym(1:3) = [0.25,0.50,0.75] 

    PARAM1%a = am 
    PARAM1%X = Xm 
    PARAM2%b = bm 
    PARAM2%Y = Ym 

    CALL MYSUB(sol1, PARAM1) 
    CALL MYSUB(sol2, PARAM2) 
    PRINT *,sol1 
    PRINT *,sol2 

END PROGRAM MAIN 

它使用含有该过程的抽象类型OBJ,然后你的派生类型可以扩展和imple实际程序。然后,您可以传递任何类型,扩展PARPASS,并将类型绑定过程OBJ转换为“MYSUB”,并从内部对其进行调用,而不用为所有不同的可能性设置单独的接口。

+0

谢谢!这将解决当前的问题,但不幸的是,这不是一个通用的解决方案。如果有人需要拨打MYSUB 3次或更多次,该怎么办?复制和粘贴MYSUB的不同PARPASS类型的副本是没有意义的,因为拥有通用子程序(在我的理解中)的想法不需要修改它。没有其他办法可以解决这个问题吗?它不应该使用派生数据类型,这只是我最初的方法。 – 2014-11-23 22:05:00

+0

@ Lord_77我添加了一个应该更具扩展性的新解决方案 – Exascale 2014-11-24 07:47:31

+0

只是一个侧面问题。难道不能将类型名称作为子例程的输入吗?所以我们称之为MYSUB,我只需要输入CALL MYSUB(sol1,'PARPASS1',PARAM1)。在这种情况下,'PARPASS1'可以是用于在MYSUB中声明PARAM1类型的字符串。 @ kyle-g – 2014-11-24 17:54:01