2014-11-22 1 views
2

최소화를 위해 일반적인 용도의 서브 루틴을 작성하려고합니다. 범용 서브 루틴을 원하기 때문에 객관적인 함수는 이름뿐 아니라 차원에서도 다른 매개 변수를 가질 수 있습니다. 그래서 매개 변수 구조를 전달할 방법이 필요합니다. (제 생각에는 Matlab에서 구조체 유형 변수와 같은 것을 사용하기 때문에 단어 구조를 사용하고 있습니다). 파생 데이터 형식을 사용할 수 있었지만 동일한 프로그램에서 두 가지 목적 함수가있을 때 문제가 발생합니다. 내가 CALL MYSUB(sol2,OBJ2,PARAM2)PRINT *,sol2로 라인을 코멘트 경우,포트란 : 임의의 "구조체"를 모듈 서브 루틴으로 전달

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 

분명히라는 모듈 : 주 프로그램 main.f90에서

:이 샘플 코드 내 코드가 원활하게 실행됩니다. 이것은 두 가지 "객관적인 함수"를 갖기 전 이었지만 지금은 MYSUB의 파생 된 유형 변수 PARPASS1이 임의적이어서는 안되기 때문에 작동하지 않습니다.

아이디어가 있으십니까?

답변

2

당신은 인터페이스를 사용하고 서브 루틴 MYSUB 과부하 수 :

MODULE MYLIB 

    USE MYPAR 
    IMPLICIT NONE 

    interface MYSUB 
    module procedure MYSUB_PARPASS1, MYSUB_PARPASS2 
    end interface 

CONTAINS 

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

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

END MODULE MYLIB 

는 그런 다음 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 유형에 대해 복사하고 붙여 넣는 것은 거의 의미가 없습니다. 일반적인 목적의 서브 루틴 (생각하면)을 수정하지 않아도되기 때문입니다. 이 문제를 해결할 다른 방법이 없습니까? 파생 데이터 형식을 사용할 필요는 없습니다. 이것은 단지 초기 접근이었습니다. –

+0

@ Lord_77 더 확장 성 있어야하는 새로운 솔루션을 추가했습니다. – Exascale

+0

그냥 부탁드립니다. 서브 루틴의 입력으로 형식 이름을 전달하는 것이 가능하지 않습니까? 그래서 우리는 MYSUB이라고 부릅니다. 단지 CALL MYSUB (sol1, 'PARPASS1', PARAM1) 만 입력하면됩니다. 이 경우 'PARPASS1'은 MYSUB에서 PARAM1의 유형을 선언하는 데 사용되는 문자열이 될 수 있습니다. @ kyle-g –