2014-11-22 94 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

相關問題