포트란 90, 모듈 by 바죠

FORTRAN 90

FORTRAN (FORmula TRANslation, 포트란)이란 무엇인가?

포트란은 엔지니어, 이공학자 및 기타 다른 과학적 알고리즘의 제작자나 사용자들을 위해 설계된 3세대 프로그래밍 언어이다. 1950년대 말에 IBM의 John Backus에 의해 기획/설계되었으며, 매우 간결하고 엄격한 구문 형식을 가지고 있으며 배우기 쉬운 것이 특징이다. 포트란의 가장 유명한 두 개의 버전은 FORTRAN IV와 FORTRAN77을 꼽을 수 있다. FORTRAN IV는 1966년에 USASI 표준으로 승인되었으며, FORTRAN 77은 1978년에 ANSI에 의해 승인된 버전이다.

ISO와 ANSI에 의해 포트란의 표준으로 새로 인정받은 것을 FORTRAN 90이라고 부르며, 1990년 초에 개발되었다. 포트란 90은 상당한 수준의 기능을 갖춘 현대화된 언어이다. 이것은 기본적으로 프로그래밍 언어 C++ 에서 지원하는 객체지향 (object-oriented) 프로그래밍 기능들과 병렬 배열 문법을 포트란77 언어에 추가한 것이다.

오늘날에는, C (C++) 또는 자바 언어가 포트란을 대부분 대체하였지만, 그러나 아직도 (?) 포트란 사용자들이 많이 있다. 그 이유는 전산 물리학 계산에서 사용해오는 전산 소프트웨어들이 다세대에 걸쳐서 계속 사용되기 때문이다. 또한 누구나 쉽게 배울 수 있다는 언어의 특징이 있다. 특정 연구그룹에서 이미 검정을 거친 루틴들이 있다. 물론, 공공적인 공간에서도 이러한 프로그램들은 존재한다. 이들을 사용하기 위해서는 포트란 언어를 알아두는 것이 필요하다는 것을 깨닫게 되는 것이다. 실제로 응용이 많이 되는 루틴들은 저 마다 오랜 역사를 가지고 있으며 포트란으로 구현되어 있는 것들이 많이 있다. 이러한 루틴들은 적극적으로 사용되어야 우리가 원하는 더 많은 일들을 할 수 있을 것이다. 포트란을 사용하지 않는 사람들도 이미 개발된 포트란 프로그램들을 읽을 수 있으면 자신들의 일에 어떠한 형태로 이든지 도움이 될 수 있다. 한 가지 확실한 사실은 현재 돌아가고 있는 소위 고성능 대용량 데이터 취급 컴퓨터 프로그램들로서 생산성 높은 프로그램들은 대부분 C나 FOTRAN 90으로 만들어져 있다는 사실이다. 병렬화해야 할 만큼 큰 데이터를 취급한다면, C 나 FORTRAN 90을 결코 무시할 수 없다.

FORTRAN 90의 특징

1. 문법이 매우 간단하여 배우기가 쉽다. (고수준 언어이다; 본질적으로 기계보다 사람에게 더 가깝게 설계되어 있다.)
2. 과학 기술 계산용 전문 언어이다. (미리 정의된 함수들 다수 보유, 113, 다양한 수치 계산 프로그래밍 모듈 지원)
3. 수식과 여러 종류의 계산등을 간단히 공식화할 수 있다. (감각적인 간결성, 묵시적 상황 판단, 추상적 자료형 지원)
4. 대상중심적이다. (동적인 메모리 관리, 모듈화의 장점을 살릴 수 있다, 확실한 데이터 처리와 보완성 확보)
5. 기종간의 호환성이 있다. (이미 검증된 많은 포트란 77 프로그램과 쉽게 연동된다.)

객체지향(대상중심)이란 ? : 특정한 응용을 위한 객체 (object)를 기술하는 높은 수준의 데이터 형, 데이터 형 처리 방법들을 정의 함으로써 프로그램을 단독으로 작성하는 것 (개발 후에 있게 되는 수정/보완 시에도 단독으로...). 프로그램 전체에서 다른 부분 사이가 독립되어 있기 때문에 이해하기 쉽고 확장과 변경이 용이한 코드를 얻을 수 있는 장점이 있다. 객체는 데이타와 함수의 모음으로 표현된다. 아래에 나타낸 것이 포트란 90과 관련된 객체지향성이다. 이들은 모듈의 작성과 깊이 연관되어 있다. 객체지향이라는 말보다는 대상중심이라는 말이 더 적합하다고 생각합니다.특정 대상을 전문으로 취급하는 데이터와 부 프로그램들을 설계하고 필요에 따라서 개발 기간동안 쉽게 계속 추가하는 것을 목표로 한다.

1. data abstraction -- user-defined types
2. data hiding -- private and public attributes
3. encapsulation -- modules and data hiding facilities
4. inheritance and extensibility -- generic procedures
5. polymorphism -- generic overloading
6. reusability -- modules

http://www.cs.rpi.edu/~szymansk/OOF90/F90_Objects.html
참고 웹자료: Introduction to object-oriented concepts using fortran90

포트란 90은 완전히 포트란 77을 포함한다. 따라서 포트란 77 프로그램은 있는 그대로 사용하는 것이 좋다. 둘 사이의 결합에도 아무런 문제점이 없다.
포트란을 사용한다면 새로 만들어지는 코드는 포트란 90으로 작성하는 것이 좋다. 물론, 기존의 포트란 77로 작성된 코드들은 철저히 재 활용 (recycling)한다는 의미이다. 즉, 검정이 완전히 끝난 코드들 (www.netlib.org)을 다시 포트란 90으로 재 작성할 필요는 없으며 그러한 일들은 많은 경우 무의미할 뿐만 아니라 오히려 위험할 수 있다. 프로그램의 테스트와 안정성을 유지하는 것이 그만큼 어려운 것이라는 것을 의미한다. 현대의 컴퓨터 언어를 기술할 때 다음의 사항들이 중점적으로 거론된다. reusability, maintainability, readability, reliability, testability.

본 웹 페이지에서는 포트란 90의 강력한 기능인 포트란 모듈의 작성에 관해서 서술하기로 한다. 현존하는 포트란 77로 작성된 코드도 사용자의 편의를 위해서 또는 사용자의 목적에 알맞게 포트란 90의 모듈로 재설계/작성하면 보다 일반적이고도 안전한 모듈이 될 수 있다. 이러한 일들은 모듈 개념을 적용하면 아주 쉽게 할 수 있다. 최소한, 현존하는 포트란 77 코드를 읽을 수 있어야 한다. 소위 엔지니어링과 사이언스를 하면서 프로그램의 신주류를 찾고 깊이 이해하여 활용하기란 매우 어렵고 또한 그러한 것들이 최고의 상황이 아닐지도 모른다. 이러한 의미에서 검정된 언어의 우수한 기능들을 점진적으로 연습하는 것이 상당히 합리적이라 할 수 있다.

왜 모듈인가?

FORTRAN 77에서는 찾아 볼 수 없는 기능이다. 대상중심 (객체지향 프로그래밍; object-oriented programming; "대상중심이라는 말이 더 어울림.) 프로그램에서만 나오는 개념이다. 모듈을 사용하면 변수와 변수 관련 함수(서브루틴 포함의 일괄적이고 보다 안전한 관리를 조장한다. 사실 FORTRAN 77은 소위 "Structured Program"을 지향했다. 쉽게 비유하면, 단 한 번에 거대한 집을 설계하는 것이다, 그 다음, 그 설계도에 맞추어서 충실히 집의 구석구석을 열심히 만들어 나가는 것이다. 물론, 이러한 아이디어 자체가 나쁘다는 것이 결코 아니다. 아주 이성적인 선택이며 분명히 좋은 방법임에 틀림없다. 하지만, 객체지향적 프로그래밍이 훨씬 프로그래밍 효율면에서 우위를 점한다는 것이 경험적으로 알려지기 시작했다.  재사용할 수 있는 단위가 모듈이다.

소위 프로그램 단위의 '재사용 (reusability)'과 변형 (modification)이 아주 쉽게, 안전하게 진행될 수 있다. 프로그램은 새로운 환경과 아이디어에 의해서 쉽게 변형되어져야 한다. 왜냐하면 프로그램은 우리의 아이디어를 적용하고 테스트하는 방법이기 때문이다. 프로그래밍이 우리의 아이디어 창출에 장애가 되면 결코 안된다. 이러한 의미에서 대상중심의 프로그래밍이 구조적 프로그래밍 보다 매우 유리하다. 특별한 아이디어를 빨리 구현하는 것이 얼마나 중요한가는 지난 컴퓨터 프로그램의 역사를 통해서 증명되었다. 속도는 차후에 개선할 수 있지만, 독창적인 아이디어의 발표는 그렇지 못하다.

"Structured Program"에서는 작성하는 프로그램이 커질수록, 다양한 전체 프로그램의 시도가 있을수록, 여러 사람과 공동으로 일할수록, 시간이 지나서 버전이 올라 갈수록, 무슨 작업들이 어디에서 일어나는지, 어떠한 계산이 진행되는지 또한 변수들에 어떠한 변화들이 일어나는지 추적하기가 점점 어려워진다. 다시 말해서, 점점 더 암호화되고 복잡해지고 그에 따른 관리가 힘들어진다는 것이다. 따라서, 새로운 프로젝트를 위한 생산성이 상당한 수준에서 위협받을 수 있다.

모듈을 사용하면 프로그램에 전체적인 변화가 분명히 있음에도 불구하고 구체적인 소스코드 상에서는 국소적인 코드 변화로 종결되는 것을 조장한다. (위에서 기술한 내용은 다소 추상적이라고 평가받을 수 있다. 보다 냉정하고 엄밀히 이야기하면 프로그래머의 습관에 관한 사항이다. 특히, 모듈을 사용하지 않는 사람들에게는 대부분 이해가 되지 않을 뿐만 아니라 언급된 대부분의 항목에 대해서 하나 하나 변론할 수도 있다는 것을 잘 알고 있다. 이것은 명백한 현실이다. 지난 세월, 사실, 세상의 프로그램들 모듈 없이도 잘 되어 왔다. 결국, 위에서 언급한 모듈의 진정한 의미는 실제 모듈을 사용해 본 다음에 평가가 내려져야 마땅할 것이다. 모듈들을 잘 설계하고 잘 사용하고 나면 그 유명한 "순서도" 조차도 특별한 의미와 필요가 없어진다면 믿어지겠는가? 주 함수에는 정말 '말하듯' 주요 명령들만이 줄지어 나타나게 된다는 것이다. 이 때 부터는 정말 프로그래머에게서 아이디어가 살아나도록 프로그램이 유도하는 수준이라고 하면 너무 심한 비약일까?)

FORTRAN 90 모듈은 무엇인가?

프로그래밍 언어 C++의 class와 비슷한 것이다. 포트란 77의 common, include, block data를 대치할 수 있다. 물론, 이것이 다는 아니다. 각종 형태의 데이터와 이들 데이터와 관련된 함수들의 연합체가 모듈이다. 다시 말해서 객체를 나타내는 수단으로 모듈이 있을 수 있다. 여기서 데이터는 미리 정해진 사이즈의 배열일 필요가 없다. 배열의 크기를 정하는 함수를 모듈 속에 하나 만들어 두고 사용할 수 있다.

FORTRAN 77에서는 공통으로 사용하는 변수들을 모아 두고 사용하는 common 문이라는 것이 있었다. common 문은 FORTRAN  77에서의 인수를 제외할 경우 유일한 global 변수의 접근 통로로 사용되었다. 소위 named common 문을 사용하여 몇 가지로 그 global 변수들을 편의상 분류하기도 했다. 하지만, 불안정한 프로그래밍의 이유가 된다고 하여 그것의 사용이 과도하게 느낄 정도로 엄청나게 천대와 탄압을 받아왔다. 하지만, FORTRAN 90에서는 보다 안전하게 모듈을 사용하여 common 문 그 고유의 장점을 살릴 수 있다. 또한 제도적으로 보다 안전하게 (save, use, public, -nly, => 키워드를 사용함으로써) 프로그램할 수 있게 되었다.

굳이 변명하자면 common 문 속의 변수들을 사용하는 함수들은 거의 정해져있다. 따라서, 이들 변수들과 이를 이용하는 함수들은 붙어서 다니는 것이 좋겠다. 이것이 모듈이다. 저장된 변수들의 접근이 명시될 수 가 있기 때문에 공통으로 사용되는 변수들의 사용에서 그 투명성이 증대된다. 여러 명이 프로그램을 개발하여 합칠 때에도 각 모듈들 간의 있을지도 모를 충돌을 제도적으로 방지할 수 있게 했다. 사실상 신경을 곤두세워서 보아야 할 변수들을 키워드 public을 이용해 목록해 두도록 되어있다. 이어지는 프로그램 수정과 확장에서도 그 탁월한 유용성이 보장된다.

자주 일어나는 일이지만, 특정 데이터를 생성하는 곳과 그 데이터를 참조하여 사용하는 곳이 멀리 (인수로 통해서 접근한다고 생각할 때) 떨어져 있으면, common 문을 사용하면 쉽게 필요로 하는 정보를 공유할 수 있다. 구차하게 필요한 정보들을 전달하고 또 전달하는 귀찮은 작업들을 할 필요가 없다. 문제는 너무 많은 작업들을 이런 식으로 하는 것은 결국 그러한 정보 관리상의 어려움을 유발하고 만다.

동적으로 크기가 변화하는 변수들도 포트란 90에서 지원되기 때문에 정확히 그 크기와 순서가 일괄적으로 정해져있는 포트란 77에서의 common 문 한계를 쉽게, 확실하게 극복할 수 있다. 사실, 이러한 위험성 때문에, 포트란 77에서는 include 문을 사용하여 완벽하게 똑같은 common 문들을 사용했었다. (예, common 문을 필요로 하는 서브루틴마다, include 'file_common_statements'를 선언하고, 해당파일만 다루는 문제마다 바꿈으로서, 일괄적으로 관리할 수 있었다.)

어떻게 해야 모듈을 잘 만들고 잘 사용할 수 있는가?

모듈을 작성할 때는 save, public (또는 private)기능들을 확실히 사용하고, 모듈을 이용할 때는 이들을 꼭 확인한다. 각각의 루틴을 작성할 때 implicit none을 항상 사용한다. 남이 만든 모듈과 내가 만든 프로그램 상에서 우연히 서로 다른 변수를 의미함에도 불구하고 변수 이름이 동등할 수 있다. 이 경우 그 숫자가 너무 많지 않고 오해의 소지가 없다면 간단히 변수이름을 재명명함으로써 슬기롭게 문제를 피해갈수 있다. 이것 또한 포트란 90의 장점이다. 위에서 지적한 implicit none은 모든 변수들의 속성이 반드시 선언되어야 한다는 의미이다. 즉, 뒤 따르는 줄에서 실수형, 문자형, 배열형, 정수형, 논리형 등이 구체적으로 정의되어야만 한다는 의미이다. 그렇지 않은 변수들의 리스트를 컴파일 시 보여주고 더 이상의 컴파일을 진행하지 않는다. 포트란에서는 컴파일할 때 보통 -C 옵션을 이용하면 배열의 한도를 넘는 배열 참조에 관련된 에러발생 위치를 실행할 때 보여주고 실행이 중단된다. 프로그램 개발 단계에서 필요한 옵션이다. 보다 더 많은 옵션들로는 다음과 같은 것들이 있을 수 있다. 단, ifort 컴파일러의 경우. 
-CB -check all -warn interface -assume realloc_lhs


포트란 90 모듈 체크 포인트:
독립적인 일들을 수행하는 하나의 모듈을 하나의 파일에 저장한다.
특정한 작업과 연관된 변수들, 배열들, 가변배열들, 해당 변수들과 밀접하게 연관된 서브루틴들, 함수들을 한 곳에 동시에 저장한다. contains 가 바로 이때 사용되는 키워드이다.
특정한 일과 연관된 작업들을 한 곳, 즉, 하나의 파일 속에 모아둔다. 외부에서는 전혀 필요하지 않은 변수들, 가변배열들, 배열들, 서브루틴들, 함수들이 있을 수 있다. 이들이 private 이다. 
외부에서는 전혀 사용할 필요가 없는 것들은 private 으로 선언해 둔다. 서브루틴, 함수,  배열, 가변배열, 변수가 private 라는 것을 적어 주어야 한다. 이들은 외부에서 USE 로 사용할 수 없다는 뜻이다.
public, private 분류가 매우 중요하다. private를 디폴트로 잡는 것이 좋다.
외부에서 사용되는 서브루틴, 함수도 public이다.
외부로부터 인수를 받을 수 있다. 이 인수는 통상의 서브루틴, 함수에서와 동일하게 취급된다.  
특정한 일을 시작할 때, 가변배열 크기를 정하고 계산이 끝날 때까지 보관할 필요가 있다. 저장하고 갱신도 해야 할 것이다. 이때 사용되는 키워드가 save이다. 
초기화 되지 않았을 때는 메모리를 잡지 않는다. 가변 배열도 외부에서 참조할 필요가 있다. 즉, 가변배열도 당연히 public 이 될 수 있다. 물론, private도 될 수 있다. public인지 private인지는  프로그래머가 직접 선택하는 것이다.  메모리 확보도 가변배열을 직접 USE 선언으로 사용할 수 있는 곳이면 프로그램 어디에서나 메모리 확보, 초기화가 가능하다.

모듈 컴파일도 독립적으로 이루어질 것이다. 특정한 패키지처럼 독립적으로 존재할 수 있다. 특정한 일을 전담할 수 있게 체계적으로 개발되어야 한다. 특정 분야일을 체계적으로 수행할 수 있으면 이상적이다. 이때, 다른 모듈을 사용하고 있다면 그 모듈을 먼저 컴파일할 것이다. 아니 먼저 컴파일되어 있어야 할 것이다.

이러한 모듈들이 많이 있을 수 있다.
특정한 일들을 전담할 수 있는 모듈들이 많이 개발되어 있어야 한다.

모듈은 다른 여러 프로그램들, 다른 여러 모듈들에서 사용되어질 것이다.
변수와 함수들이 사용되어질 수 있다. USE, ONLY라는 키워드를 사용하는 것이 좋다.
하나의 프로그램에서 여러번 사용될 수 있다. 한 번만 사용될 수도 있다.

하나의 모듈 속에서 정의 된 변수는 그 모듈 안에서만 광역 변수가 될 수 있다.
모듈 속에 있는 함수들에서 공통으로 사용되어진다. 특수한 일을 하기 때문에 인수로 전달하는 것이 번거롭다. 모듈 속에서는 공통으로 사용되어지는 변수가 있다. 또한, 외부의 다른 프로그램들에서 볼 수 있다면 그곳에서 초기화될 수 있고, 그곳에서 변수 갱신이 가능하다.
이러한 작업 대신에 인수로 특정 값들을 전달할 수 있다. 이러한 경우, 특정 값이 모듈 속에서 초기화 될  수 있다. 인수를 통한 변수 초기화도 가능하다. 사용자 입장에서는 인수를 통한 작업 초기화가 더 이해하기 쉽다. 모듈을 작성한 사람은 그렇지 않을 수 있지만. 하지만, 가능한한 숨길 수 있는 것은 숨기는 것이 좋다. 그렇게 해서 모듈의 독립성을 높일 수 있다. 다른 데이터와 한 꺼번에 뒤엉켜서 노출될 필요가 없다. 최대한 private 로 갈 수 있는 것들은 private로 가야한다. 그래야 사용하기 편한 모듈이 되는 것이다. 모듈의 취지가 그런것이다. public 한 것을 최소화하고, private 한것들로 일을 하자, 그리고 숨길 수 있는 것들은 최대한 숨기자, 세상에 내놓을 필요가 없는것들은 모두 private이다.
외부 프로그램과 연동될 때, 가능하면 인수로만 데이터를 주고받을 수 있다. 굳이 USE로 통신을 할 필요가 없을수도 있다.
USE 를 사용하면 서브루틴, 모듈, 메인 프로그램 어디에서도 사용할 수 있다. 참조할 수 있고 갱신할 수 있다.



USE stack, local_use_pop => pop
pop가 특정 함수에서 국소적으로 사용될 때, stack 모듈 속의 pop는 local_pop로 재명명되었다.

USE stack, ONLY: pos, local_pop=> pop
모듈 stack속의 pos와 pop만이 사용 가능하다. 다만, 이 경우 모듈 속 pop의 경우 local_pop로 이름이 다시 만들어졌다.

모든 모듈들은 그것을 사용하는 프로그램 단위 보다 먼저 컴파일되어야 한다. 이렇게 되기 위해서는 makefile에서 아래와 같은 프로그램들간의 의존성이 필요하기도 하다. 즉, 프로그램 ximage_lbfgs.f90은 모듈 timpose.f90를 사용하게 되어있다. 이 때 이 모듈은 다른 파일 속에 있는 것이며 이전에 만들어진 것이다.

USE aaa
USE bbb ! 모듈 bbb에서 public한 모든 변수, 배열, 또는 부 프로그램(function, subroutine)들은 모두 사용할 수 있다.
USE ccc
USE ddd, ONLY: qqq,ppp ! 모듈 ddd에서 사용하고자하는 변수, 배열, 또는 부 프로그램 (subroutine, function) 이름들을 적어둔다.

특정 모듈을 사용할 때, "USE 모듈이름은 아주 앞 쪽에 선언된다. 즉, 그 모듈을 사용하는 서브루틴에서 모든 변수들 보다 앞서서 선언된다. 결국, implicit none 보다 앞서서 그 바로 윗줄에서 정의된다. 즉, 컴파일할 때 먼저 불러져서 컴파일이 될 수밖에 없다. USE lll, ONLY: sss 등과 같이 ONLY를 많이 사용할수록 프로그램의 readability는 당연히 높아지게 된다. 보다 더 확실하게 변수들을 사용한다는 것이다. 일반적으로 ONLY를 사용하는 것이 사용하지 않는 것보다 유리하다. 구조적으로 많은 것들을 체크할 수 있다. 뜻하지 않게, 모듈속의 변수를 바꾸어 버릴 수 있다. 이런 경우는 대개, USE만 사용한 경우에 발생한다. ONLY함께 사용하면 이런 경우를 원천 차단할 수 있다. 프로그래밍 실수를 원천적으로 줄일 수 있다.

ximage_lbfgs.o:ximage_lbfgs.f90 timpose.o
$(cmpl) $(Ocft) ximage_lbfgs.f90

ximage_lbfgs.o를 만들기 위해서는 timpose.o가 먼저 필요하게 된다는 것입니다. 또는 timpose.f90이 수정되었다면 다시 컴파일되어야 합니다. 이러한 변화에 발 맞추어서 ximage_lbfgs.o도 반드시 다시 컴파일되어야 한다는 의미입니다. 여기에서, 재미있는 것을 얻을 수 있습니다. 프로그램의 버전이 올라갈 때마다 (또는 프로그램 개발 중에), 변화가 상당히 국소적으로 일어남을 알 수 있습니다. 즉, 프로그램의 전체적인 변화가 분명히 있음에도 불구하고 구체적인 소스코드 상에서의 변화는 상당히 국소적인 변화로 종결될 수 있음을 보여주고 있습니다. 이것이 바로 대상중심 프로그램의 장점 중의 하나입니다. 즉, 전체 설계도를 보지 않아도 된다는 것입니다. 프로그램이 크게 바뀔 때마다 모듈의 형태로 추가될 수 있다면 이 또한 보기 좋을 것입니다.

한 가지 재미있는 것은 아래와 같다. 여러 모듈 속의 변수들을 이제는 너무 쉽게 접근하고 바꿀 수 있어지니까 '모듈 사용의 도'를 넘어 오히려 전체 프로그램을 못 읽어 버리게 만들 수 있다는 사실이다. 찬찬히 생각하면서 모듈의 기능과 전체 프로그램의 흐름을 다시 생각해 볼 필요가 있다. 이러한 경우 새로운 모듈들의 재정립이 필요하다.

IMPLICIT NONE에 관해서: 어떠한 것도 묵시적이지 않다고 선언하는 것이다. 즉, 모든 변수들이 구체적인 형을 선언해 주어야 한다는 것이다. 이렇게 선언한 이상. REAL*8, INTEGER, CHARACTER*3, LOGICAL, COMPLEX*16 과 같이 모든 변수에 그 해당 변수형을 선언해야 한다. 이러한 것은 프로그램 작성시 발생한 TYPO들을 잡아주는 기능을 한다. 조금 귀찮지만 안전한 코드 생성에 일조한다. 더욱이, 모듈 개념을 사용할 때는 꼭 있어야 한다는 생각이 든다. 왜냐하면, USE를 사용하는 경우, 사용하는 모듈 속에 변수들이 존재하는지를 컴파일하는 단계에서 강제로 확인 시켜준다.

이전에 많이 사용했던 IMPLICIT REAL*8 (A-H,O-Z) 즉, 시작하는 변수들이 A-H 또는 O-Z로 시작하면 실수형임을 선언하는 어찌 보면 너무나도 광범위한 선언은 프로그램 작성과 관리차원에서 그렇게 좋은 선택은 아니다. 복잡한 프로그램을 만들다 보면, 항상 사용하는 변수들이 선언되게 하는 implicit none의 힘을 느낀다. 뻔한 내용의 실수들을 줄일 수 있도록 도와주는 힘. 뻔한 실수들을 잡아내기가 더욱 어려울 때가 종종있다. 전혀 예측하지 않은 형태의 착오이기 때문이다.


변수 선언은

INTEGER, DIMENSION(:), ALLOCATABLE, SAVE, PRIVATE :: ivari_name 처럼 사용될 수 있다. 너무 길어지는 면이 있지만, 변수하나의 특성을 표현하기 위해선 어쩔 수 없다. 실제로는 이와같이 하지 않는 경우가 많다. INTEGER, ALLOCATABLE :: ivari_name(:) 정도로 해두고 private와 save는 보통, 상당히 앞 쪽에서 미리 따로 선언하는 경우가 많다. 또한 재 선언을 통해서 public 또는 private를 확인해 줄 수 있다.

implicit none
private
save
integer .....
real*8 .......
real*8, allocatable ::
integer, allocatable ::
logical ..........
public :: ..........(부)함수이름, 변수이름, 바로 위에서 선언된 (가변)배열 이름들이 포함 되는 경우가 많이 있다.

USE를 사용할 때에도

USE xmodulex, ONLY: ivari,jvari,isubp,ifunc 처럼 ONLY를 사용해서 구체적으로 함수와 변수들을 명시해주는 것이 보기에 좋고 프로그래밍에서 실수할 확률을 줄일 수 있도록 도와 준다. 프로그램 시작과 함께 변수값이 할당될 수도 있다. 이 경우는

integer :: iiijjj=10, kkklll=100
logical :: on=.true., off=.false.
real*8 :: qqq=1.10d0, ttt=2.20d0
real*8 :: aaa(-1:1)=(/ -1.d0, 0.0d0, 1.d0 /)

통상의 구조는 어떠한가? (제법 많을 일들을 수행하는 경우) = (특정 데이터의 크기를 모듈 외부와의 통신을 통하여 정하고, 필요하면 디스크로부터 정보를 읽어 들이고, 또는 생성하고, 연관된 계산들을 수행하고, 주요 데이터들을 모듈 외부로 보내고/받고, 특정 배열을 소멸시키고, 주요 정보를 디스크에 저장하고, 프린트하고,.....)

module common_data
implicit none
private
save
integer iii1,jjj1
real*, allocatable :: aa1(:,:),bb1(:)

logical first_call ! 첫 번째로 모듈이 사용되는 경우가 중요한 경우가 있다. 이를 위해서 전역변수로 선언해 둘 수 있다. 초기화를 .true.로 해두고, 나중에 .false.로 바꿀 수 있다.

character*2, allocatable :: ccc1(:)
.........

public :: aa1,bb1,iii1

end module common_data


module common_data2
implicit none
private
save

.........

public :: ..........
end module common_data2



program abcd
implicit none
........
............
..................
....................
..........
........

contains

subroutine aaa
USE common_data
implicit none
............

end subroutine aaa

subroutine bbb
USE common_data2, ONLY : w,y,z
implicit none
............

end subroutine bbb

subroutine ccc
USE common_data
implicit none
............

end subroutine ccc

subroutine ddd
USE common_data2, ONLY : x,y,z
implicit none
............

end subroutine ddd

subroutine eee
implicit none
...........

end subroutine eee

function fff
implicit none
...........
end function fff

end program abcd

implicit none 뒤에는 각종 변수, (가변) 배열들이 선언될 수 있다. 상당히 짧은 프로그램의 경우 위와 같은 형식으로 해결될 수 있다. 일반으로, 사용되는 모듈들의 숫자가 많아 질수록 대부분의 경우 여러 개의 파일들을 사용한다. 보통 한 파일 속에 모듈 하나를 넣어 두는 경우가 많다. 위의 경우에는 모듈들은 데이터 저장 창고로 사용된 예이다. 하지만, 모듈은 특정 데이터들을 보관할 뿐만 아니라 관련된 데이터 처리를 할 수 있도록 설계되었다. 즉, 모듈= {데이터들}+{데이터 처리 부함수들}이기 때문이다. 모듈이 변수들 없이 함수들만 포함(contain)할 수도 있다. 반대로 변수들만 가질 수도 있다.

program ssss
USE xxx, ONLY : aa1,bb1,pbc
USE yyy, ONLY : qq,pp,ssq
USE www
implicit none
REAL*8 ss
REAL*4 t_s
INTEGER itemp,itemq,irate
CHARACTER*8 fnnd ; CHARACTER*10 fnnt
real*8, allocatable :: vector(:)
integer ierr
.............
.............

CALL DATE_AND_TIME(date=fnnd,time=fnnt)
write(6,'(1x,a10,2x,a8,2x,a10)') 'date,time ', fnnd,fnnt
...............
...........

CALL SYSTEM_CLOCK(itemp,irate)
..................
......................................
.....................

write(6,*) epsilon(ss),' epsilon for real*8'
write(6,*) epsilon(t_s),' epsilon for real*4'
2.2204460492503131E-016 epsilon for real*8
1.1920929E-07 epsilon for real*4

write(6,*) floor(4.8d0)
write(6,*) floor(-4.8d0)

4
-5

write(6,*) huge(ss)
write(6,*) huge(t_s)
1.7976931348623167E+308
3.4028235E+38

write(6,*) minexponent(ss)
write(6,*) minexponent(t_s)
-1021
-125

write(6,*) nint(-6.8999)
write(6,*) nint(-6.1119)

-7
-6

가장 큰 수를 찾고자 할 때
max0(j,k,l,...)
amax0(a,b,c,d...)
ifix(aa)버림을 실행하여 정수로 반환

min0(i,j,k,...)
amin0(a,b,c,...)
sign(x,y)
는 abs(x)*(y 값의 부호)를 반환한다.

mod()
MOD (3.0, 2.0) 1.0
MOD (8, 5) 3.
MOD (-8, 5) -3.
MOD (8, -5) 3.
MOD (-8, -5) -3.

int()
정수로 변환
INT (-3.7) -3.

nint() Nearest integer.
NINT (2.789) --> 3.
NINT (2.123) --> 2.

aint()

(n/2)*2
n=11
8
n=11
10
n=-9
-8

포트란 90에서의 수학

DOT_PRODUCT(vector1,vector2)
MATMUL(matrix1,matrix2)
MAXVAL()
MINVAL()
SUM()

== .eq.
/= .ne. 비교: C 언어, 파이썬에서는 !=을 사용한다.
>= .ge.
<= .le.

위의 경우처럼 '='이 관련된 경우에서 =이 항상 뒤쪽에 위치한다.
> .gt.
< .lt.


논리연산에는 .not., .and., .or.가 있다.

.not. ( (la == lb) .and. ( .not.(lc /= ld) ) ) 처럼 논리 연산에 직접 사용될 수 있다.

if(.not. allocated(vector))then
allocate(vector(100000), stat=ierr)
if(ierr /= 0) then
write(6,*) 'problem'
stop
endif
endif

allocate(vector(-89:100)) 처럼 정의될 수 있다. -89, -88, -87,.....98, 99, 100. 즉, allocate(vector(100)) 는 크기가 100인 vector가 생성됨을 의미한다. 물론, 1부터 시작하여 100까지 간다는 말이다. allocate(vector(1:100))과 동등한 표현이다. 디폴트가 1부터 시작한다는 이야기입니다.
...............

if(allocated(vector)) deallocate(vector)

CALL SYSTEM_CLOCK(itemq)
write(6,'(2e15.4,2x,a9)') float(itemq-itemp)/float(irate)/60.,float(itemq-itemp)/float(irate)/3600.,' min or h'

end program ssss

-------------

모듈을 이용하는 간단한 하나의 프로그램을 보자.

!234567890

MODULE wf_wr
IMPLICIT NONE
save
public
integer nsim
real*8 temper
real*8, allocatable :: wf(:),wr(:)

END MODULE wf_wr

메인프로그램 바로 시작해도 된다. 아래와 같이
USE wf_wr
IMPLICIT NONE
real*8 tol,sol,sol1,sol2
real*8 tmp
integer i
real*8 bennetteq,zeroin

temper=1.d0
nsim=10
allocate(wf(nsim),wr(nsim))

wf=1.
wr=-1.

do i=1,nsim
call random_number(tmp)
wf(i)=wf(i)+0.2*(tmp-0.5)
call random_number(tmp)
wr(i)=wr(i)+0.2*(tmp-0.5)
enddo

sol1=maxval(wf)
sol2=minval(wf)
write(6,*) sol1,bennetteq(sol1)
write(6,*) sol2,bennetteq(sol2)

tol=1.d-16
sol=zeroin(sol1,sol2,bennetteq,tol) 이 함수는 netlib에서 다운로드 받은 함수이다. root finding 프로그램이다. 유저가 공급할 함수명: 이 경우 bennetteq이다.
write(6,*) sol,bennetteq(sol)

deallocate(wf,wr)
stop
end

function bennetteq(sol) 유저가 사용할 함수
USE wf_wr
IMPLICIT NONE
real*8 sol
real*8 bennetteq
integer i

bennetteq=0.0d0
do i=1,nsim
bennetteq=bennetteq+1.0d0/(1.d0+exp((wf(i)-sol)/temper))-1.0d0/(1.d0+exp((wr(i)+sol)/temper))
enddo
return

end

module xxx
implicit none
private
save

모듈 내에서 공통으로 사용되고 저장될 변수들.....global object 선언 (전역 객체 선언)
이곳에, 모듈 내에서 정의되는 함수 이름(real*8, integer, logical 등을 선언할 필요는 없다. 모듈 내에서 각자 정의될 때만 필요하다.


logocal first_call
...........
public :: ............변수, 가변 배열, 부함수 (subroutine, function) 이름들...

contains

subroutine xxx_initialize(...)
implicit none
first_call=.true.
...........지역 변수들 local variables

end subroutine xxx_finalize

subroutine xxx_finalize(...)
implicit none
...........지역 변수들

end subroutine xxx_finalize

subroutine xxx_do_something(...)
USE xxx, ONLY : xxx1,yyy1,sub_name,fn_name
implicit none
...........지역 변수들

주의할 점: 지역변수들을 선언할 때, 전역변수와 이름이 같은 것을 사용해 버리면 어떻게 될까? 답은 간단하다. 이름이 같은 것조차 의미없는, 진정한 의미로, 한번 지역 변수는 그 지역에서 지역변수이다. 하지만, 이렇게 복잡하게 프로그래밍할 필요가 없다. 혼돈을 피하기 위해서, 지역변수들은 될 수 있는 한 전역변수와 같은 이름을 사용하지 않도록 하는 것이 바람직하다.

모듈 속의 서브루틴에서 이 모듈 속에 속하지 않는 외부의 서브루틴, 함수들도 당연히 사용할 수 있다. 독립적으로 선언된 모듈 속의 내용(변수들, 부함수들)이라면 당연히 USE를 사용해야 한다. 예전에 만들어진 포트란 77 프로그램과 함께 연동될 경우, 특히, common문이 있는 경우에도 common 문을 그냥 사용해도 된다. 왜냐하면 포트란90은 포트란 77을 다 이해하기 때문이다.
end subroutine xxx_do_something

subroutine xxx_print 모듈 속의 부함수들은 인수를 가지지 않을 수도 있다.
USE www 또 다른 모듈의 변수,함수를 사용할 수 있다.
USE zzz, ONLY : sfa 또 다른 모듈의 변수,함수를 사용할 수 있다.
implicit none
..........

end subroutine xxx_print

function x_test()
implicit none
real*8 x_test ! 모듈 속의 함수 선언 : 이곳에서 함수 선언하는 것만으로 충분하다. 다만, 전역 변수 선언 공간에서, 이 친구가 private, public이라는 것만 밝혀두면 된다.
end function x_test

end module xxx

-------------------------

마찬가지로 module yyy도 고유의 모듈 형식을 가질 수 있다. module www, zzz등도 있어야 컴파일이 된다.

모듈 내부에서만 저장되거나 생성되는 변수, 내부에서만 이용되는 부함수
모듈 외부에서 (USE 명령을 통해서 사용) 참조가능한 변수, 부함수 등에 유의하여 작성한다.
MODULE x_mo_du_le
IMPLICIT NONE
PRIVATE ! 디폴트를 어떻게 잡느냐의 문제; 기본이 private이고 public에 해당하는 것들은 표식적으로 명시해야 함을 나타내고 있다.
SAVE
INTEGER :: ia,ib,ic,id,ie,if.................
REAL*8, ALLOCATABLE :: arr(:,:), brr(:,:), crr(:,:)..............(특정한 순간에 크기가 할당될 배열들이다.)(계산/저장 후)(특정 순간에 할당된 정보가 없어질 수 있다.)
PUBLIC :: abc_initial, abc_final,variable_1,array_1,ia,ib,.........서브루틴, 함수명, 위에서 선언된 변수들, 필요한 것만 직접 적어둔다.

이 영역에서는 공통으로 사용되는 변수,배열,가변배열들을 선언해준다. 아래에 선언될 함수, 서브루틴들에 의해서 참조될 뿐만 아니라 변화될 수 있다. 물론, 외부에서 참조되고 변화될 수 있다. 외부에서 사용하는 경우 USE라는 명령을 사용하여 그곳에서 특정 모듈 내용을 사용하게 된다. 여기서 주목할 것은 private 과 public이다. 처음에 private으로 시작했기 때문에 이 영역에서 선언된 것들은 이 모듈이 사적으로 사용한다는 뜻이다. 즉, 이 모듈 밖에서는 이 변수가 보이질 않는다. 따라서 예기치 않은 상황의 연출로부터 바뀔 염려가 없다. 완전히 보전된다. 다만, 뒤에 마음이 바뀌어서 구체적으로 public (즉, 밖에서 사용할 수 있는 subroutine 이름이나 배열, 정수, 실수 등을 )을 이용하여 선언해준다. 즉, 기본 사적사용에 공적사용 명시인 것이다. 위에서 선언된 save는 기본적으로 모든 변수들이 이 모듈이 사용되는 동안 그 값이 계속 저장된다는 것이다. 연이어서 이 모듈을 사용할 때 이전 값들이 그대로 유지되어야 한다고 선언하는 것이다. private, public을 사용하지 않으면 public으로 간주된다. 따라서 첫 줄에 private를 사용하지 않았다면,마지막에 private를 이용하여 현 모듈에 있어서 사적인 것들의 리스트를 만들어 두면 좋다. 예를 들면, 아래와 같다.
public :: aa, bb, cc
public :: aa_subroutine, bb_subroutine, cc_function 이렇게 public으로 선언된 것들은 원하는 모듈 또는 부 함수들에서 USE, ONLY들을 이용하여 선택적으로 사용할 수 있다.

CONTAINS ! 뒤에 따르는 함수들을 나열하기 전에...;물론, 서브루틴, 함수들은 위에서 선언된 변수들을 중점적으로 관리할 서브프로그램들일 것이다. 즉, 특정 대상 중심의 서비스.
! 국소 변수들로 argument형식으로 외부와 통신할 수 있다. 하지만 주요 정보들은 이곳에서 계산되고, 이곳에 저장되면 될 것이다.
! 일반으로, 본 모듈 내에서만 정의되고, 사용되는 변수들과 부함수들도 있다. (이들을 private이라고........... )
! 모듈 외부에서 접근/사용 가능한 변수들과 부함수들===>public이라고......
! 외부와 통신하는 부함수들은 자체적으로 인수들을 가질 수 있다. 국소적인 인수들이다. 위에서 선언된 모듈 내의 변수들과는 명목적으로 상관이 없는 변수들을 인수로 가지고 있다. 인수들을 가지지 않는 부함수들도 있다. 이 경우 이미 주요한 변수들이 위에서와 같이 정의된 경우, 원하는계산만 수행할 경우 특별히 인수가 없을 수도 있다.

통상 외부 함수 (주 프로그램,서브루틴, 함수에서 접근 가능한 subroutine들이 예를 들어 3개 정도는 있을 수 있다. 물론, 충분히 많은 수 일 수 있다.; 모듈 내부에서 만 사용되는 변수/부함수들도 있을 수 있다. 필요한 일들을 충분히 분업화 시킬 수 있다는 의미이다. 위에 선언된 모듈 내에서만 정의되어 보호되는 변수들을 전문으로 취급하는 부 함수들을 많이 만들 수 있다. 특정한 데이터들만을 전문으로 다루기 때문에 이러한 부 프로그램들은 통상 private형식인 것이 자연스러운 일일 것이다. 이와는 반대로, 외부와 직접 정보를 교환하는 부프로그램은 당연히 public 형식일 것이고 (다시 말해서, 외부에서 접근가능한 부 프로그램임을 의미한다.) 필요에 따라서, 용도에 따라서, 인수들 (변수, 배열을 가질 수 있다.

SUBROUTINE abc_initial(n_problem_size,...)
IMPLICIT NONE ! 통상 main함수로부터 불려지면서 (따라서 public이어야 한다.) 현 모듈과 관련하여 필요한 메모리를 확보한다. 또는 변수 초기화를 시도한다.
INTEGER n_problem_size ! 일반적으로 주 (main) 프로그램에서 인수들을 통해서 문제의 크기를 정해줄 수 있다. 직접 필요한 정보를 읽어들여도 됨.
INTEGER i1_local,i2_local
REAL(8) r1_local,r2_local
.............

일반적으로 총체적인 입력들을 정리해 줄 수 있다. 실질적으로 풀려는 문제가 구체화되고, 정의된다. 사실, 관련 모듈의 특성화가 시작된다.
ALLOCATE(aa(n_problem_size))
ALLOCATE(bb(n_problem_size)) ! 모듈 내에서 언제든지 접근가능하다. 물론, public이면 외부에서도 접근가능함.
...............

END SUBROUTINE abc_initial

SUBROUTINE abc_final()
IMPLICIT NONE
INTEGER i1_local.....! main 함수로부터 불려지면서 (따라서 public이어야 한다.) 불 필요한 메모리를 지운다.
REAL*8 r1_local,r2_local
...............

일반적으로 이 모듈과 관련된 일들을 종료하기 전 총체적인 출력 정리를 해 줄 수 있다. 필요한 정보들 출력, 예를 들면.

DEALLOCATE(aaa)
DEALLOCATE(bbb)
....................

END SUBROUTINE abc_final

SUBROUTINE aaaaa1() ! 서브루틴, 함수의 인수가 하나도 없을 경우도 있을 수 있다.
IMPLICIT NONE
INTEGER i1_local,i2_local
REAL*8 r1_local,r2_local

................구체적으로 이 모듈 내에서 할 일 들과 연관이 있는 일을 최대한 분업화할 수 있도록 한다.

여러 개의 서브루틴과 함수를 정의한다. 모듈 내에서는 많은 인수들이 필요하지 않다. 왜냐하면 모듈 내에서 대부분의 변수들이 접근가능하기때문이다.

인수가 하나도 없는 함수도 물론 가능하다. 즉, subroutine unaaa, 부를 때 call unaaa 형식이 가능하다. argument를 이용하여 외부와 최소한의 통신은 가능하도록 하는 것이 일반적이다. 모듈 내에서 사용되는 다양한 변수들은 외부 모듈들 속의 변수들 또는 다른 모듈들과의 접촉을 차단한 채 그들만을 위하여 특별히 만들어진 부 프로그램들에 의해서 다루어진다. 모듈의 개념을 도입하면 앞서 이야기한 특정 대상을 중심으로 프로그램들이 쉽게 만들어진다. 상황이 이러하니 인수들을 많이 가지지 않는 것이 당연하다.

END SUBROUTINE aaaaa1

SUBROUTINE internal_use1
IMPLICIT NONE
INTEGER i1_local,i2_local
REAL*8 r1_local,r2_local

현 모듈 내에서만 사용되는 부함수가 일반으로 많이 있을 수 있다. 인수가 있을 수도 없을 수도 있다. 물론, 목적과 설계에 따라서 달라질 수 있다. 모듈 속에서 선언된 전역변수들만 집중적으로 취급하는 경우는 모듈 속 서브루틴, 함수들은 인수의 숫자가 적어질 수밖에 없다. 물론, 모듈 외부와 통하는 경우에는 일반으로 인수들의 숫자가 증가할 가능성이 많을 것이다.

END SUBROUTINE internal_use1

FUNCTION qqq() ! 서브루틴, 함수의 인수가 하나도 없을 경우도 있을 수 있다.
IMPLICIT NONE
REAL*8 qqq
INTEGER iq_local,
REAL(8) qx_local
..............

RETURN ! 없어도 된다. subroutine의 경우에도 return없어도 된다.
END FUNCTION qqq

이 영역은 필요한 함수나 서브루틴들을 만들어서 두는 곳이다. 통상의 인수 (arguments)들은 최소화되어 몇 개밖에 되질 않을 것이다. 왜냐하면 이 모듈 내에서 공통으로 사용되면서 계속 저장되는 (save) 변수들은 이미 모듈 전역 변수들로 정의되어 있기 때문이다. 또한 필요에 따라서 데이터들을 저장하는 배열들을 생성시킬 수 있다.

이 경우에는, 모듈 내의 함수들은 외부에서 집중적으로 불려지는 것(주요 함수)과 한 번 정도 불려지는 것들(_initial, _final) 등으로 분류될 수 있다. 또한 현 모듈 내에서만 불려지면서 사용되는 서브 프로그램들이 있다. 모듈 속에 선언된 전역 변수들도 마찬가지이다. 모듈 내에서만 사용되는 변수들도 일반적으로 있을 수 있다.

END MODULE x_mo_du_le

이 모듈을 사용하려면 사용하고자 하는 함수, 주 프로그램, 또는 서브루틴 내에 USE x_mo_du_le (물론, USE x_mo_du_le, ONLY : xxx 처럼 선언하는 것이 더 강력한 프로그래밍 습관이다.)이라고 선언해 준다. 하지만, 그 선언되는 위치는 주의해야 한다. 보통 implicit none 위에서 선언한다. 엄청나게 앞에서 선언되는 것이다. 현 함수에서 선언되는 변수들 보다 항상 앞선다는 것이다. 여러 개의 모듈들은 동시에 사용할 경우 연속해서 한 줄 단위로 추가하여 적어두면 될 것이다. 이렇게 하면 앞서 이야기한 public이 허용하는 부함수들 또는 (가변) 변수들이 현 함수 내에서 접근/조작이 가능해지는 것이다. 물론, 각 모듈들 내에서 private변수들은 현 함수에서 볼 수가 없다. 만약, 현 함수에서 implicit none을 사용했다면, 프로그램들을 컴파일할 때 즉시, 잘못 사용되고 있는 변수들을 찾아낼 확률이 상당히 높아지는 것이다. (물론, 이것이 프로그래밍에서 함정이 될 수 도 있다. 우연히 지역변수를 선언하고 사용하고 있는데, 이것이 다른 모듈 속에서 온 것으로 착각하고 프로그램을 하는 경우이다.) 이러한 자체 체크 기능은 상당히 중요한 의미를 부여한다. 여러 명이 동시에 일을 하다보면 뜻하지 않은 일들이 많이 발생하게 된다. 혼자 프로그램을 만들어도 마찬가지이다. 항상 그 내용과 이름을 다 기억하고 있을 수는 없을 것이다. 시간이 지나고 다음에 다시 조금 수정할 때에도 마찬가지이다. 안전사고의 미연 방지는 아무리 강조해도 지나치지 않다.

포트란 프로그램에서 `시스템 콜하기`; 파이썬과의 결합? 포트란 프로그램에서 CALL SYSTEM('application.py')처럼 파이썬 스크립트를 직접 불러서 사용할 수도 있다. 이러한 경우 call system이전에 필요한 자료들을 파일로 정리해둔 다음 시스템으로 잠시 나간 다음 시스템에서 준비된 파이썬 스크립트가 자료를 사용할 수 있게 설계할 수 있다. 물론 외부의 프로그램들 (스크립트에서 준비) 등으로 자료처리 또는 계산을 수행한 다음 다시 포트란 프로그램으로 되돌아 오는 방법이 있다. 물론 돌아오기 전에 포트란 프로그램에서 자료를 읽어들일 수 있도록 파일들을 미리 만들어주면 좋겠다, 물론 파이썬 스크립트가 관리를 해야 할 것이다. 마지막으로 포트란 프로그램에서 준비된 자료들을 읽어들여서 계속하여 포트란 프로그램으로 계산을 수행할 수 있다.

자료 적어두기: 파일열기/적기 == 포트란 명령으로 수행
call system('python_driver.py') == 포트란에서 빠져 나와서 파이썬 스크립트 실행하기.
자료 읽어들이기: 파일 열기/읽기 == 포트란 명령으로 수행
유닉스 프롬프트 상에서 아래와 같이 abc.exe라는 실행화일을 실행시키면
nohup abc.exe >output_file_name &
사용자 계정에서 로그아웃해도 프로그램 실행이 죽지 않는다.

generic 함수들을 모듈이라는 틀을 이용하여 잘 만들어 두면 매우 유용한 함수 사용이 이루어질 수 있다.
예를 들어 아래와 같이 첨부된 모듈은 문자열 처리와 데이터 수집을 위한 것이다. 실수, 정수를 처리하기 위해서는 각각의 프로그램을 만들어야 하지만, 인수의 타입에 따라서 그 기능을 자동적으로 나누어서 수행할 수 있는 하나의 함수를 만드는 것이 모듈을 사용하면 가능하다. http://incredible.egloos.com/4836430
strings.txt

USE 모듈명, ONLY : 배열, 가변배열, 변수명, 함수, 서브루틴
이렇게 올 수 있다.
물론, 해당 모듈 속에서 이들이 모두 public으로 선언이 되어 있어야 한다. 
 함수, 서브루틴, 변수 이름들이 모두 각각 public으로 선언 된 경우에만 다른 곳(모듈, 서브루틴, 함수, 메인 프로그램)에서 사용될 수 있다.


모듈을 이용하여 일반화된 함수들을 만들어 낸 경우: 즉, 일반적으로 사용할 수 있는 바꾸기 계산을 수행하는 무리의 프로그램들을 모두 한꺼번에 묶어둔 경우.

MODULE Genericswap
  IMPLICIT NONE
 
  INTERFACE Swap
    MODULE PROCEDURE Swapint, Swapreal, Swapstring
  END INTERFACE
 
CONTAINS
 
  SUBROUTINE Swapint(a, b)
    INTEGER, INTENT(IN OUT) :: a, b
    INTEGER :: temp
    temp = a ; a = b ; b = temp
  END SUBROUTINE Swapint
 
  SUBROUTINE Swapreal(a, b)
    REAL, INTENT(IN OUT) :: a, b
    REAL :: temp
    temp = a ; a = b ; b = temp
  END SUBROUTINE Swapreal
 
  SUBROUTINE Swapstring(a, b)
    CHARACTER(*), INTENT(IN OUT) :: a, b
    CHARACTER(len(a)) :: temp
    temp = a ; a = b ; b = temp
  END SUBROUTINE Swapstring
END MODULE Genericswap
 
PROGRAM EXAMPLE
  USE Genericswap
  IMPLICIT NONE
  INTEGER :: i1 = 1, i2 = 2
  REAL :: r1 = 1.0, r2 = 2.0
  CHARACTER(3) :: s1="abc", s2="xyz"
 
  CALL Swap(i1, i2)
  CALL Swap(r1, r2)
  CALL Swap(s1, s2)
 
  WRITE(*,*) i1, i2   ! Prints 2 and 1
  WRITE(*,*) r1, r2   ! Prints 2.0 and 1.0
  WRITE(*,*) s1, s2   ! Prints xyz and abc
END PROGRAM EXAMPLE
-------------------------------------------------------------


http://ihlee.kriss.re.kr/compphys/f90module.htm
fortran90_for_physicist.pdf
Computer_programming_2008.pdf

-------------------------------------------------------------
-------------------------------------------------------------
상당히 다른 스타일로 설명되어진 유용한 포트란 90 참고자료들:
coursenotes.ps
f90studentnotes.ps
-----------------------------추천 파일---------------------
pdf형식
f90_coursenotes_.pdf
f90_studentnotes_.pdf
-------------------------------------------------------------
KISTI  제공 포트란 책자: F90_book.pdf

참고 자료:  포트란 90 기본
http://incredible.egloos.com/3044862

-------------------------------------------------------------

http://wwwasdoc.web.cern.ch/wwwasdoc/f90.html
http://www.nsc.liu.se/~boein/f77to90/f77to90.html
http://wwwasdoc.web.cern.ch/wwwasdoc/WWW/f90/f90.html
http://www.liv.ac.uk/HPC/HTMLFrontPageF90.html
http://www.cisl.ucar.edu/tcg/consweb/Fortran90/F90Tutorial/tutorial.html
http://www.liv.ac.uk/HPC/HTMLF90Course/HTMLF90CourseSlides.html
http://www.star.le.ac.uk/~cgp/prof77.html
http://www.chem.ucl.ac.uk/resources/history/people/vanmourik/images/Fortran%2095-manual.pdf
http://www.physics.udel.edu/~bnikolic/teaching/phys660/PDF/introductory_f90.pdf
https://docs.oracle.com/cd/E19957-01/806-3593/806-3593.pdf
-------------------------------------------------------------

http://www.personal.psu.edu/faculty/h/d/hdk/fortran.html
Fortran Resources
and
Fortran 77/90/95 Compilers for Windows and Linux

--------------------------------------------------------------------------------------------------------------------
http://flash.uchicago.edu/~tomek/htmls/num_meth.html
Numerical methods for Fortran programmers






http://www.g95.org/index.shtml
Personal Computer, Windows용 컴파일러, g95-MinGW-41.exe  다운로드:
http://ftp.g95.org/g95-MinGW.exe
SilverFrost FTN95 (Windows):
http://www.silverfrost.com/11/ftn95/ftn95_fortran_95_for_windows.aspx


전설속의 포트란 코딩 폼:
fortran_coding_form.pdf

포트란 90 사용자 가이드 (SUN) :
FORTRAN_90_USERS_GUIDE_SUN.pdf

-------------------------------------------------------------------------------------------------



-------------------------------------------------------------------------------------------------


핑백

덧글

  • JBang 2010/11/24 02:09 # 답글

    형님.. 좋은 자료 감사합니다. 많은 도움 되었습니다.

    P.S : 결국 제가 미국 나오기 전에 연락 못드렸네요. 죄송합니다. 담에 또 연락 드릴게요.
  • 바죠 2010/11/24 09:57 # 삭제

    아 미국이군요!
    잘 지내시길 바랍니다.
  • JBang 2010/12/03 04:22 # 삭제 답글

    포트란에서..
    모듈이 아닌 메인함수에서 public, allocatable 한 변수를 선언 할수 있나요?

    제가 하고 싶은게 메인에서 allocatable 한 변수를 선언하고, subroutine 안에서 그 변수를 allocate을 한 뒤, 여기 저기 다른 함수들에서 사용하고 싶은데, 이게 쉽지가 않습니다.

  • 바죠 2010/12/03 09:15 # 삭제

    global이란 이름으로 모듈를 하나 선언하시면 됩니다.
    그리고 이 모듈은 변수들만 존재하는 것이될 것입니다.
    사용하고 싶은곳 모두에서 USE명령어를 사용하시면 원하신는 것 모두를 얻을 수 있습니다.
    물론, subroutine argument로는 사용하실 수 없습니다.

  • 바죠 2010/12/03 10:03 # 삭제

    module common_data

    implicit none

    private

    save

    integer iii1,jjj1

    real*8, allocatable :: aa1(:,:),bb1(:)

    logical first_call ! 첫 번째로 모듈이 사용되는 경우가 중요한 경우가 있다. 이를 위해서 전역변수로 선언해 둘 수 있다. 초기화를 .true.로 해두고, 나중에 .false.로 바꿀 수 있다.

    character*2, allocatable :: ccc1(:)



    .........



    public :: aa1,bb1,iii1



    end module common_data

  • JBang 2010/12/03 06:19 # 삭제 답글

    한가지 방법을 찾았습니다.

    여전히 모듈을 사용하긴 하는데..

    1, 모듈 내에서 type을 이용해 allocatable 변수 형태를 만들고,

    2, 이 모듈안에 subroutine에서 type으로 선언한 변수를 allocate한다

    3, 이 type형태 변수를 메인함수에 선언하고 모듈안 subroutine을 이용해서 변수를 allocate한수 사용하다.

    조금 복잡합니다. ㅎㅎ

    이렇게 메인에서 선언한 함수를 subroutine에서 allocate를 할수 있긴 한거 같은데.. 정확히 이게 왜 가능한지는 모르겠네요.

    형이 알고 계신 다른 방법 있어요?
  • 바죠 2010/12/03 10:06 # 삭제

    MODULE v_globy ! arrays to be shared.....

    IMPLICIT NONE

    PUBLIC

    SAVE

    REAL(8), ALLOCATABLE :: v_global(:,:)

    INTEGER, ALLOCATABLE :: i_global(:)

    INTEGER ii,jj,kk

    REAL(8) aa,bb,cc, ddd(100,10)

    END MODULE v_globy ! 가변 배열을 포함하는 형식이다.
  • JBang 2010/12/03 06:24 # 삭제 답글

    아. 그리고 한가지 더 궁금한게 있어요.

    C에서는 pointer 개념과 포트란에서 pointer개념이 다른거 같던데요.

    정확히 어떻게 되는지 궁금하더라고요.

    느낌에 포트란에서는 allocateable과 거의 똑같이 쓰는거 같던데.. 맞습니까? 아님 차이점이 어떻게 되는지 궁금합니다.
  • 바죠 2010/12/03 09:45 # 삭제

    소위, equivalence 형식으로 사용됩니다.
    즉, 이미 확보된 메모리에 덮어서 사용되는 양식입니다.
  • 바죠 2010/12/03 09:18 # 삭제 답글

    포트란 90에서 매우 특수한 경우들(리스트, 매우 전문적인 경우들)을 제외하고는 포인터 변수를 사용하지 않습니다.
  • JBang 2010/12/04 03:05 # 삭제 답글

    감사합니다. 형님. ^^
  • CORE 2014/08/06 22:20 # 삭제 답글

    안녕하세요, 글 잘읽고 갑니다. 포트란 77만 사용하다 포트란 90, 2003으로 넘어가려고 하는데요, USE문에서 ONLY는 단순히 가독성을 위해 쓰는 것인가요 아니면 다른 장점(메모리측면에서라던지)들이 있는것인가요? 만약 가독성만을 위해서라면 주석문과 같다고 보면 되는것인가요?
  • 바죠 2014/08/07 08:22 # 답글

    말씀하신 가독성 부분에서도 도움이 됩니다.
    하지만, 가독성 때문에 사용하는 것은 아닙니다.
    혹시 모를 실수를 잡아낼 수 있는 안전장치의 기능이 더욱더 크다고 보시면 됩니다. 원천적으로 변수 이름이 같을 수 있습니다. 전혀 의도하지 않았던 상황에서 말입니다.

    통상 모듈 속에서 선언된 변수들이 있습니다.
    마찬가지로 독립적인 서브루틴/프로그렘에서도 변수들이 있습니다.
    따라서, 변수 이름은 언제든지 같은 이름을 가지는 변수가 될 수 있습니다. 그런데, 서로 다른 프로그램 개발 시기 때문에 예상하지 못한 실수를 할 수 있습니다. 단순히 USE를 사용하다보면 있을 수 있는 일입니다.
    하지만, ONLY를 추가로 사용하면, 컴파일러 단계에서, 체크가 가능하기도 하고 (중복 사용, 또는 배제), 프로그램 만들 때, 확실하게 인식을 할 수 있습니다.
    메모리 측면에서의 이득은 전혀 없습니다.

    특별한 경우가 아니면, ONLY를 사용해서 손해볼 경우는 없습니다. 무조건 프로그래머에게 유리한 것입니다. 가독성도 당연히 높아집니다.
    프로그램이 보다 더 명백해지죠.
    저는 100 % ONLY와 더불어 USE 사용합니다.
  • gut! 2017/03/17 23:48 # 삭제 답글

    유용한 글 잘보고 갑니다. 이제막 시작하는 단계인데 도움이 많이 됐습니다
댓글 입력 영역