[Fortran] 포트란을 활용한 인터페이스 : 개요, 외부 프로시저, 내부 프로시저, INTENT, 모듈

 정보

  • 업무명     : 포트란을 활용한 인터페이스 : 개요, 외부 프로시저, 내부 프로시저, INTENT, 모듈

  • 작성자     : 이상호

  • 작성일     : 2020-12-03

  • 설   명      :

  • 수정이력 :

 

 내용

[개요]

  • 안녕하세요? 웹 개발 및 연구 개발을 담당하고 있는 해솔입니다.

  • Fortran (포트란)은 수식 (Formular) 변환기 (Translator)의 약자로 과학 계산용으로 주고 사용되는 언어입니다.

  • 복잡한 계산 수행 성능이 뛰어나 공학과 자연과학 등 특정분야에 주로 사용되며 기상 데이터 처리를 위해 널리 사용되고 있습니다.

  • 오늘 포스팅은 포트란을 활용한 인터페이스를 소개합니다.

 

 

[특징]

  • 기상 데이터 처리를 위해서 포트란 (Fortran)기술이 요구되며 이 프로그램은 이러한 목적을 달성하기 위한 기술서

 

[기능]

  • 개 요

  • 외부 프로시저

  • 내부 프로시저

  • INTENT

  • 모듈

 

[활용 자료]

  • 없음

 

[자료 처리 방안 및 활용 분석 기법]

  • 없음

 

[사용법]

  • 없음

 

[사용 OS]

  • Linux (CentOS v7.8)

 

[사용 언어]

  • gfortran v4.8.5

 

 세부 내용

개요
  • 서브루틴과 함수를 말하는 프로시저는 메인 프로그램에 포함돼 있는 내부 프로시저와 메인 프로그램이나 모듈에 포함되지 않고 독립적으로 존재하는 외부프로시저 그리고 모듈 프로시저가 있습니다.

  • 메인 프로그램과 외부 프로시저는 서로 분리된 독립적인 프로그램 단위입니다. 

  • 메인 프로그램과 프로시저는 다른 프로시저에서 지역적으로 선언된 변수들에 접근 할 수 없으며 마찬가지로 외부 프로시저는 메인 프로그램에 선언된 변수에 접근 할 수 없습니다. 

  • 한 프로그램 단위에서 다른 단위로 정보를 전하기 위해서 함수에 인수를 전달하여야만 가능합니다.

  • 내부 프로시저는 하나의 프로그램 단위에 포함돼 있으므로 프로시저에 대한 참조에 대해서 인수의 개수와 타입 등의 속성들과 함수의 리턴 값 등이 바르게 사용 되었는지를 컴파일러가 점검할 수 있습니다. 

  • 비슷하게 모듈에 포함되는 모듈 프로시저 역시 모듈내의 문장으로 참조되거나 모듈에 대한 USE문을 사용함으로써 컴파일러가 인수와 결과 등이 올바른지 점검할 수 있도록 할 수 있습니다. 

  • 이와 같이 모듈 또는 내부 프로시저는 기본적으로 명시적 인터페이스 (explicit interface)를 가져 인수의 사용과 리턴 값 등에 대해 컴파일러가 오류를 점검할 수 있습니다. 

  • 반면 외부 프로시저는 메인 프로그램이나 다른 프로그램 단위와 분리되어 독립적으로 존재하므로 컴파일러가 프로시저에 대한 참조의 오류 여부를 점검할 수 없습니다. 

  • 외부 프로시저는 기본적으로 암시적 인터페이스 (implicit interface)를 가집니다.

 

외부 프로시저
  • 포트란에서는 인터페이스 블록(interface block)을 이용하여 외부 프로시저에 대해 명시적 인터페이스를 제공합니다.

  • 인터페이스 블록은 컴파일러에게 프로시저 인수의 모양, 형태 등의 속성을 알려 주어 프로시저에 대한 참조의 오류 여부를 점검할 수 있도록 해줍니다.

  • 인터페이스 블록의 일반적인 형태는 다음과 같습니다.

PROGRAM exercise

  INTERFACE 
    SUBROUTINE squrt(a,n)
      REAL :: a(n) 
    END SUBROUTINE 
  END INTERFACE 
  
  INTEGER, PARAMETER :: m = 100 
  REAL :: q(m) q=71
  
  CALL squrt(q,m) 
END PROGRAM exercise

 

  • 이렇게 인터페이스 블록을 사용하여 외부프로시저에 대한 명시적 인터페이스를 정의해주면 다음과 같은 예제처럼 컴파일 단계에서 에러가 발생해 의도치 않은 코딩 실수를 줄일 수 있습니다.

PROGRAM inter
  INTERFACE 
    REAL FUNCTION ratio(x, y) 
      REAL::x, y 
    END FUNCTION ratio 
  END INTERFACE 
  
  INTEGER :: i=3, j=25
  
  PRINT *,'The ratio is ',ratio(i,j) 
END PROGRAM inter 

REAL FUNCTION ratio(x, y) 
  REAL:: x, y 
  ratio=x/y 
END FUNCTION ratio

 

  • 위 예제는 메인프로그램과 외부 프로시저의 인수타입이 일치 하지 않아 컴파일 단계에서 다음과 같은 에러가 발생합니다.

"test.f", line 9.34: 1513-061 (S) Actual argument attributes do not match those specified by 
an accessible explicit interface. 
** inter === End of Compilation 1 === 
** ratio === End of Compilation 2 === 
1501-511 Compilation failed for file test.f

 

내부 프로시저
  • 프로그램 단위 내에 함수나 서브루틴 같은 프로시저가 올 수 있으며 이를 내부 프로시저라 합니다.

  • 모든 내부 프로시저는 그것을 포함하는 프로그램 단위의 맨 마지막 부분에서 CONTAINS문 다음에 위치해야 합니다.

  • 외부 프로시저와 그 형태는 동일하나 단지 END문 다음에 FUNCTION 또는 SUBROUTINE을 반드시 붙여 주어야 한다는 점이 다릅니다.

  • 내부 프로시저를 포함하는 프로그램 단위에서 선언된 변수는 내부 프로시저에서 접근할 수 있으며 내부 프로시저에서 다시 정의할 수도 있습니다.

  • 다음은 외부 프로시저에서 작성된 예제에서 인터페이스블록을 사용하지 않고 내부 프로시저를 이용하도록 수정 한 것입니다.

PROGRAM explicit 

  INTEGER :: i=3, j=25 
  PRINT *,'The ratio is ',ratio(i,j) 
  
CONTAINS 
  REAL FUNCTION ratio(x, y) 
    REAL:: x, y 
    ratio=x/y 
  END FUNCTION ratio 
END PROGRAM explicit

 

  • 내부 프로시저는 명시적 인터페이스가 기본이므로 위 예제는 다음과 같이 컴파일러에 의해 오류가 발견됩니다.

"inter.f", line 3.31: 1513-061 (S) Actual argument attributes do not match those specified by 
an accessible explicit interface. 
** inter === End of Compilation 1 === 
1501-511 Compilation failed for file inter.f.

 

INTENT
  • 포트란에서는 보다 효율적인 컴파일 성능향상을 위해 INTENT 속성(attribute)을 이용해 프로시저내의 더미 인수들에 대한 계획된 이용(in, out, 또는 inout)을 컴파일러에게 알려 줄 수 있습니다.

    • INTENT(in) : 프로시저에 들어와서 나갈 때까지 값이 변함없는 인수

    • INTENT(out) : 프로시저 내에서 값을 할당 받을 때까지 사용되지 않는 인수

    • INTENT(inout) : 프로시저에 들어와 사용되고 값을 새로이 할당 받아 그 결과를 호출한 프로그램에되돌려 주는 인수

SUBROUTINE meron(a, b, c, m, n) 
  REAL, DIMENSION(n, n), INTENT(IN) :: a 
  REAL, DIMENSION(m, m) :: b, c 
  INTENT(out) :: b 
  INTENT(inout) :: c 
  
  c = SQRT(c) 
  b = c + SUM(a) 
END
! 인수 a는 프로시저 내에서 값이 변하지 않는다.
! 인수 b의 값은 프로시저 내에서 값을 할당 받을 때까지 사용되지 않는다.
! 인수 c는 프로시저 내에서 사용되고 값이 새로 할당된다. 

 

  • 포트란 프로그램에서 INTENT 속성을 반드시 사용해야 하는 것은 아닙니다.

  • 그러나 INTENT 속성을 사용함으로써 컴파일러는 코딩 오류 점검이 빨라지고 프로그램의 안정성을 높일 수 있습니다.

  • 만약 INTENT(in) 속성의 인수가 값을 할당 받거나 INTENT(out) 속성의 인수가 새로운 값을 할당 받지 않는다면 컴파일 단계에서 에러가 발생하게 될 것입니다.

  • 다음 예제처럼 INTENT 속성을 잘못 지정해 준 경우 컴파일 단계에서 에러가 발생 할 것 입니다.

PROGRAM intent_err
REAL :: x, y 
  y = 5. 
  CALL mistaken(x, y) 
  PRINT *, x 

CONTAINS 
  SUBROUTINE miserr(a, b) 
    IMPLICIT NONE 
    REAL, INTENT(in) :: a
    REAL, INTENT(out) :: b 
    
    a = 2*b 
  END SUBROUTINE miserr
END PROGRAM intent_err

 

모듈
  • 모듈은 타입선언, 서브프로그램, 새로운 데이터 타입선언 등을 하나로 묶어 정의 할 수 있는 프로그램 단위로서 Fortran90에 새롭게 추가된 기능입니다.

  • 사용자는 모듈을 사용해서 보다 신뢰성 있고, 재사용이 쉬우며 작성하기도 쉬운 객체 기반의 코드를 작성할 수 있습니다.

  • 모든 프로그램 단위는 USE문을 이용해 모듈을 첨부할 수 있고 그렇게 해서 그 모듈이 제공하는 기능을이용할 수 있습니다.

  • Global Object Declaration

    • 모듈은 Fortran77의 COMMON과 INCLUDE문을 대신해 사용됩니다. 글로벌 데이터 설정이 필요한 경우 하나의 모듈에 그 데이터를 정의해 둡니다.

    • 이렇게 모듈에 정의된 데이터는 그 모듈을 첨부하는 어떤 프로그램 단위에서도 사용될 수 있으며 그 값은 각각의 모듈 첨부에 대해 일정하게 유지됩니다.

  • Interface Declaration

    • 인터페이스에 대한 정의도 모듈에 해두고 명시적 인터페이스가 필요할 때마다 모듈을 첨부해 사용할 수 있습니다.

  • Procedure Declaration

    • 프로시저를 모듈에 정의해서 그 모듈을 첨부한 어떤 프로그램 단위에서도 사용할 수 있도록 합니다.

  • Controlled Object Declaration

    • 접근 구문을 이용해 모듈에서 선언된 변수, 프로시저, 연산자 등의 노출 정도 (visibility)를 제어할 수 있습니다.

  • Packaged of Whole Sets of Facilities

    • 사용자 정의 타입, 프로시저, 연산자, generic 인터페이스 등을 정의하고 하나로 묶을 수 있어 간단한 객체 지향성을 제공합니다.

  • 모듈 프로그램 단위의 기본 모양은 다음과 같습니다.

MODULE <module name>
  <declarations and specifications statements>
    [CONTAINS
  <definitions of module procedures>]
END [MODULE [<module name>]]
<module name>은 USE문에 사용되는 이름이고 파일명과 같을 필요는 없습니다.

 

  • Global data

    • 글로벌 변수를 모듈에 정의해 두면 이를 필요로 하는 프로그램은 USE문을 이용해 모듈을 첨부하여 글로벌 변수에 접근할 수 있습니다.

MODULE global 
  REAL :: a, b, c 
  INTEGER :: i, j, k 
END MODULE global

 

  • 위와 같이 정의된 모듈 globals를 첨부시키기 위해 프로그램 단위는 다음과 같이 USE문을 사용할 수 있다. 

  • 단, USE문은 프로그램 단위에서 제일 위에 위치해야 합니다.

USE globals ! 모든 변수 접근 가능
USE globals, ONLY: a, c ! a,c 특정 변수만 사용 가능
USE globals, r => a, s => b ! 지역변수 r,s를 이용하여 a,b 변수 접근 가능

 

  • Procedure

    • 모듈은 다른 프로그램 단위가 접근할 수 있는 프로시저를 포함할 수 있습니다. 

    • 모듈 내에 위치하는 모듈 프로시저도 내부 프로시저와 같이 다음과 같은 점을 제외하고는 외부 프로시저와 동일한 모양을 가집니다.

      • CONTAINS 문 다음에 위치 해야 합니다.

      • END 문 다음에 FUNCTION 또는 SUBROUTINE이 있어야 합니다.

MODULE module_pro
  TYPE point 
    REAL :: x, y 
  END TYPE point 
  
CONTAINS 
  FUNCTION addpoints (p, q) 
    TYPE (point), INTENT(IN) :: p, q 
    TYPE (point) :: addpoints
    addpoints%x = p%x + q%x
    addpoints%y = p%y + q%y
  END FUNCTION addpoints
END MODULE module_pro

PROGRAM sum_p
  USE module_pro
  TYPE (point) :: px, py, pz
  
  px = point(1., 2.) 
  py = point(2., 5.) 
  pz = addpoints(px, py) 
  
  PRINT*, ' pz =', pz
END

 

 참고 문헌

 문의사항

[기상학/프로그래밍 언어]

  • sangho.lee.1990@gmail.com

[해양학/천문학/빅데이터]

  • saimang0804@gmail.com