소프트웨어를 이용한 연구와 수업을 위해 도커와 깃허브를 이용한 연구 프로젝트 템플릿을 만들어서 공개했습니다. 도커를 이용하면 소프트웨어와 관련된 라이브러리를 설치하고 환경을 설정하는 과정을 쉽게 만들 수 있고, 깃과 깃허브를 이용하면 도커 설정 파일과 프로그래밍 소스 코드를 안전하게 관리할 수 있습니다. 도커 사용 경험이 없는 연구자들이 도커를 쉽게 사용할 수 있도록 프로젝트 템플릿에 도커 관련 리눅스 스크립트들을 추가하였습니다.
소프트웨어 기술 발달에 따라 점점 더 많은 과학자와 공학자들이 연구를 위해 컴퓨터 소프트웨어와 프로그래밍 도구들을 사용하고 있다. 소프트웨어를 이용한 연구에서는 환경 설정, 재현성 및 소스 코드 손실과 같은 문제들이 발생할 수 있다. 이 해설에서는 리눅스 컨테이너와 버전 관리 시스템을 사용하여 이러한 문제를 방지하는 방법에 대해 조사하였다. 연구 프로젝트 단위로 클라우드 저장소를 통해 코드를 관리하고 리눅스 컨테이너에 연구 환경을 구축하면 위의 문제들을 방지하고 협동 연구를 더 쉽게 만들 수 있다. 리눅스 컨테이너 사용경험이 없는 연구자들을 위해 컨테이너 생성과 실행에 필요한 스크립트를 포함한 연구 프로젝트 템플릿 저장소를 공개하였다.
대학원에서 연구를 위해 또는 수업을 위해 프로그래밍을 사용하는 경우가 있습니다. 프로그래밍 언어를 이용해 직접 프로그램을 개발할 경우 소스 코드를 관리해주는 프로그램을 버전 관리 시스템이라고 합니다. 버전 관리 시스템을 이용하면 소스 코드 변경 사항을 기록하여 필요할 경우 이전 상태로 되돌릴 수 있고, 실수로 코드를 지워도 복구가 가능합니다. 대학원생들에게 다양한 버전 관리 시스템들 중 깃(Git)을 추천합니다.
주요 Git 명령어들
Git에서 주로 사용하는 명령줄(Command line) 명령어들은 아래와 같습니다. 명령줄이 익숙하지 않은 학생들은 GUI 프로그램을 이용해도 됩니다.
git init: 현재 디렉토리를 git 저장소로 만들어줍니다.
git add <files>: 파일들(새 파일 또는 수정한 파일)의 변경 사항을 추적하겠다고 git에게 알려줍니다.
git commit: 앞에서 추적하기로 한 변경 사항들을 실제로 기록합니다.
git status: 현재 저장소 상황을 보여줍니다. 추적 중인 파일들 중 어떤 파일들이 변경되었는지 알 수 있습니다.
git diff: 어떤 내용들이 변경되었는지 확인합니다.
git log: 그동안의 commit 내역을 확인합니다.
git clone <remote>: 원격 저장소가 있을 경우 원격 저장소를 현재 컴퓨터에 복사합니다.
git pull: 원격 저장소에서 최신 변경 사항을 가지고 옵니다.
git push: 현재 저장소에서 commit한 변경 사항을 원격 저장소에 기록합니다.
소스 코드에 주요 변경 사항이 있을 때마다 git add, git commit 명령을 실행합니다. 위의 명령어들은 일단 변경 사항을 저장하기 위한 명령어들이고 문제가 생겼을 때 복구하기 위한 명령어들이나 branch(가지 치기) 기능과 관련된 명령어들도 여러 가지가 있습니다. 평소에는 add, commit 명령으로 소스 코드 변경 사항을 잘 기록해두고 다른 명령어들은 필요할 때 찾아서 사용하면 됩니다(한글판 Pro Git 책).
GitHub
원격 저장소가 필수는 아니지만 사용중인 컴퓨터 전체에 문제가 생겼을 경우에는 git으로도 소스 코드를 복구할 수 없기 때문에 중요한 코드라면 별도의 컴퓨터에 원격 저장소를 만들어두는 것이 좋습니다. 원격 저장소로 사용하기 좋은 클라우드 서비스들이 몇 가지 있는데 그중 깃허브(GitHub)를 가장 많이 사용합니다. GitHub를 사용하면 다른 사람과 공동으로 작업하기도 좋습니다.
GitHub에 저장소를 만들고 작업중인 컴퓨터에서 clone하면 GitHub 저장소가 자동으로 원격 저장소로 등록되기 때문에 컴퓨터에서 코드를 수정하고 add, commit한 후 push해서 GitHub 저장소를 업데이트할 수 있습니다. 이미 컴퓨터에 git 저장소가 있을 경우에는 GitHub에 새로운 저장소를 만들고 작업중인 컴퓨터에서 GitHub 저장소를 원격 저장소로 등록해주면 됩니다. 이 때 필요한 명령은 GitHub에서 새로운 저장소를 만들면 자세히 설명해줍니다.
GitHub를 이용하면 작업중인 컴퓨터와 GitHub 두 군데에 소스 코드를 백업하는 셈입니다. 여러 대의 컴퓨터에서 작업하더라도 GitHub를 통해 소스 코드를 쉽게 동기화할 수 있습니다. 프로그래밍이 본인의 연구에서 중요하다면 꼭 버전 관리 시스템을 사용합시다. git add/commit/push를 기억합시다.
본 연구실에서는 파동 전파 모델링을 위해 병렬 프로그래밍을 사용하고 있습니다. 최근 GPU 성능 향상에 따라 GPU를 이용한 파동 전파 모델링과 완전 파형 역산도 진행하고 있습니다. 그동안 진행해 왔던 GPU 관련 과제들은 다음과 같습니다.
2014-2019 자원개발특성화대학사업 – 산학협력 연구단 석유가스 물리탐사
2015-2016 한국지질자원연구원 – GPU를 이용한 파동 전파 모델링 기술 개발, GPU를 이용한 속도 모델링 기술 개발
2016 부산과학기술기획평가원 – 범용 그래픽 처리장치와 OpenACC를 이용한 병렬 컴퓨팅 성능 향상
2017-2019 한국지질자원연구원 – 다중 GPU 기반 고성능 역시간 구조보정 성능 비교 연구
2019-2020 국방과학연구소 – 저주파 수중음향 전달특성 및 고속화 성능 분석
병렬 프로그래밍 기술은 탄성파 탐사 분야 뿐 아니라 물리학, 기계, 조선이나 화학 공학의 전산 유체 시뮬레이션 분야에서도 중요하게 사용되는 기술입니다. 특히 GPU 계산은 CPU를 이용한 계산보다 빠르고 효율적이기 때문에 대학/연구소/기업 등에서 연산 성능 향상 및 비용 절감을 위해 수요가 점점 증가하고 있습니다. 그러나 안타깝게도 부산 지역에 GPU 프로그래밍을 하는 사람이 많지 않기 때문에 GPU 병렬 프로그래밍 도입에 어려움을 겪는 사례들이 있습니다.
올해 여름에 부산대학교 조선해양공학과 교수님으로부터 쇄빙선에 가해지는 빙하중을 시뮬레이션하는 프로그램을 GPU에서 빠르게 돌아가도록 만들어달라는 제안을 받고 방학 기간 동안 작업을 진행했습니다. 부산대에서 OpenMP와 MPI를 이용해 클러스터 컴퓨터에서 돌아가도록 개발한 프로그램을 자체적으로 GPU용으로 바꿨는데 성능이 안 나와서 본 연구실에서 GPU 프로그램의 성능을 향상시키는 작업을 수행했습니다. 그 결과 클러스터 컴퓨터에서 CPU 56 코어를 사용해 8시간 30분 정도 걸리던 벤치마킹 모델 시뮬레이션 작업이 GPU 최적화를 통해 Nvidia Tesla V100 GPU 카드 한 장을 사용했을 때 30분 정도로 단축되었습니다. 여러 장의 GPU를 사용할 수 있도록 개선하여 GPU 카드 네 장을 사용하면 10분 정도에 결과를 얻을 수 있습니다. 해당 연구는 최근 대한조선학회에 발표했습니다.
현재 대학원 수업에서 병렬 프로그래밍을 다루기는 하지만 컴퓨터 관련 학과가 아니다보니 GPU 성능 최적화에 대해 깊이 다루지는 않습니다. 평소 컴퓨터와 프로그래밍에 관심이 있고 고성능 병렬 프로그래밍에 대해 배우고 싶다면, 본 연구실에 들어와서 병렬 연산 쪽으로 연구하는 것도 좋겠네요. 병렬 프로그래밍에서 주로 다루는 언어는 Fortran/C/C++/CUDA 이니 해당 언어 사용 경험이 있다면 더 좋습니다.
‘실용주의 프로그래머’는 전문 프로그래머들을 위한 조언들이 담긴 책입니다. 제가 대학원생 때 읽고 책의 조언들 중 몇 가지를 직접 실천해보면서 많은 도움을 얻었습니다. 총 70가지의 조언들이 담겨 있는데 제가 실천했던 조언들 중 몇 가지만 살펴보겠습니다.
11. DRY (Don’t Repeat Yourself) – 반복하지 마라.
12. 재사용하기 쉽게 만들라.
21. 명령어 셸의 힘을 사용하라.
연구하면서 반복적으로 하는 작업들이 있습니다. 대학원생 때 반복적으로 하던 작업들 중 이진 파일로 된 탄성파 자료나 속도모델 등에서 trace나 profile을 추출하는 작업, 지하 영상에 미분이나 라플라시안 필터를 적용하는 작업, 깊이에 따라 속도가 선형으로 증가하는 속도모델을 만드는 작업 등이 있었습니다. 그때 그때 코드를 새로 작성하거나 예전에 사용했던 코드를 수정해서 작업했었는데 이러한 반복 작업을 없애기 위해 명령어 셸에서 옵션만 바꿔가며 쉽게 재사용할 수 있는 프로그램들을 작성했었습니다. 그리고 그런 프로그램들을 모아 gpl 라이브러리라고 이름을 붙였죠. 주로 당시 사용하던 포트란 프로그래밍 언어로 프로그램들을 작성했는데, 명령어 셸에서 사용할 수 있도록 option parser도 만들고 파일 입출력도 많이 다루면서 프로그래밍 연습을 할 수 있었습니다.
22. 하나의 에디터를 잘 사용하라.
리눅스 Command line 상에서 프로그래밍을 했기 때문에 당시 사용할 수 있는 에디터로 Vim과 Emacs가 있었습니다. 둘 중 어느 것을 사용할까 비교해보다가 결국 어디에나 설치되어 있는 Vi(Vim)를 사용하기로 했고, 각종 명령어와 plugin들을 이용해 Vim 고급 사용법을 익혔습니다.
23. 언제나 소스코드 관리 시스템을 사용하라.
당시에는 Mercurial을 선택해서 사용하다가 몇 년 전부터는 Git만 사용하고 있습니다.
28. 텍스트 처리 언어를 하나 익혀라.
당시 포트란과 C 언어만 사용하고 있었는데, 이 책을 읽은 후 Ruby, Perl, Python 중 프로그래머를 행복하게 하자는 철학을 내세웠던 Ruby를 선택해서 공부하고 사용했었습니다. Ruby를 배워놓았던 것이 도움이 돼서 나중에 Ruby와 Seismic Unix를 이용해 Muting/Interpolation 스크립트도 작성할 수 있었습니다. 참고로 지금은 Ruby는 사용하지 않고, 과학/공학 라이브러리가 많은 Python을 주로 사용합니다.
위의 조언들 외에도
20. 지식을 일반 텍스트로 저장하라.
29. 코드를 작성하는 코드를 작성하라.
36. 모듈간의 결합도를 최소화하라.
49. 소프트웨어를 테스트하라.
61. 수작업 절차를 사용하지 말라.
68. 문서가 애초부터 전체의 일부가 되게 하고, 나중에 집어넣으려고 하지 말라.
등 다양한 조언들을 실천해보면서 프로그래밍 실력을 향상시킬 수 있었습니다. 우리가 전문 프로그래머는 아니지만 주로 프로그래밍을 이용해 연구를 수행하고 있으니 프로그래밍에 대해 공부하는 것도 많은 도움이 됩니다. 단, 이것 자체가 연구는 아니니 연구하는 중에 틈틈이 연습해보는 것이 좋겠죠.
속도모델에서 프로파일을 추출하여 깊이에 따라 속도 그림을 그려보겠습니다. 이진 형식의 속도파일에서 텍스트 파일로 프로파일을 추출한 후 그리는 방법과 이진 속도파일을 직접 읽어서 그리는 방법을 살펴보겠습니다. 참고로, 탄성파 공통송신원모음 등에서 트레이스를 추출하여 그리는 과정 또한 동일합니다.
텍스트 파일로 추출하여 그리기
바이너리 파일에서 프로파일 또는 트레이스를 추출하기 위해 gpl 라이브러리의 gplTracePick 프로그램을 사용하겠습니다. 이차원 단면(속도모델, 공통송신원모음 등)에서 세로 방향 트레이스를 추출할 때 사용하는 프로그램입니다. (가로방향 트레이스는 gplHTracePick 프로그램을 이용하면 됩니다.) 이 프로그램을 그냥 실행하면 아래와 같은 도움말이 나옵니다.
%%sh # 이 글을 쓰고 있는 jupyter notebook에서 shell 명령을 실행하기 위한 magic command입니다.
gplTracePick # 실제 터미널상에서 실행하는 명령어
Gpl trace picker
Required parameters:
[i] n1= : # of grids in fast dimension
[s] fin= : input binary file
[s] fout= : output binary file
[i] pick= : (=first), first pick (1~n2)
Optional parameters:
[i] last=first : last pick (pick~n2)
[i] step=1 : pick step
[f] d1=1.0 : grid size
[i] n2=calc : # of grids in slow dimension
[s] type=f : data type [ifdcz]
[s] otype=a : output type [ab] (ascii/binary)
위에서 n1, fin, fout, pick은 프로그램 실행시 필수적으로 넣어줘야 하는 값입니다.
n1은 세로 방향(fast dimension) 격자수
fin은 입력 파일 이름
fout은 출력 파일 이름
pick은 추출하고자하는 가로 방향(slow dimension) 격자 번호입니다. 격자 번호는 1번부터 시작합니다.
Marmousi 속도모델(nx=576, ny=188, h=0.016 km)에 대해 1.6 km 지점(격자번호 101)에서 시작하여 3.2 km 간격(200개 격자 간격)으로 3개의 속도 프로파일을 추출한다면 아래와 같이 실행할 수 있습니다.
텍스트 파일로 추출한 결과는 gnuplot과 같은 프로그램을 이용해 빠르게 확인해볼 수 있습니다. 여기서는 파이썬의 Matplotlib을 이용하여 위의 속도 프로파일을 그려보겠습니다.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
trc=np.loadtxt("vel_profile.txt")
h=0.016
fs='large'
plt.figure(figsize=[15,5])
for i,ix in enumerate([100,300,500]):
plt.plot(trc[:,0],trc[:,i+1],label="{0} km".format(ix*h))
plt.legend(loc="upper left",fontsize=fs)
plt.xlabel("Depth (km)",fontsize=fs)
plt.ylabel("Velocity (km/s)",fontsize=fs)
<matplotlib.text.Text at 0x10cc66c88>
이진 파일을 직접 읽어서 그리기
이번에는 파이썬에서 이진 형식의 속도모델 파일을 직접 읽어서 그려보겠습니다.
nx=576
ny=188
vel=np.fromfile("marm16km.bin",dtype=np.float32)
vel.shape=(nx,ny)
h=0.016
fs='large'
depth=np.arange(ny)*h
plt.figure(figsize=[15,5])
for ix in [100,300,500]:
plt.plot(depth,vel[ix,:],label="{0} km".format(ix*h))
plt.legend(loc="upper left",fontsize=fs)
plt.xlabel("Depth (km)",fontsize=fs)
plt.ylabel("Velocity (km/s)",fontsize=fs)
<matplotlib.text.Text at 0x10d13dd30>
참고로, 파이썬은 배열 인덱스가 0번부터 시작하기 때문에 가로방향 100, 300, 500번 속도 프로파일을 가져다가 그렸습니다(gplTracePick을 이용하는 앞의 예제에서는 101, 301, 501번 격자 위치에서 추출했죠).
탄성파 트레이스 그리기
공통송신원모음에서 탄성파 트레이스를 추출하여 그리는 과정은 속도모델에서 프로파일을 추출하여 그리는 경우와 동일합니다. 아래는 샘플 개수가 723개, 샘플링 간격 4 ms, 트레이스가 96개인 공통송신원모음 파일(marm3000.bin)에서 31번째와 61번째 트레이스를 그리는 예제입니다.
ntr=96
ns=723
dt=0.004
trc=np.fromfile("marm3000.bin",dtype=np.float32)
trc.shape=(ntr,ns)
fs='large'
time=np.arange(ns)*dt
plt.figure(figsize=[15,5])
for itr in [30,60]:
plt.plot(time,trc[itr,:],label="trace {0}".format(itr+1))
plt.legend(loc="upper left",fontsize=fs)
plt.xlabel("Time (s)",fontsize=fs)
plt.ylabel("Amplitude",fontsize=fs)
plt.xlim([0,ns*dt])
두 번째 방법은 python의 matplotlib 라이브러리를 이용하는 방법입니다. 이를 위해서는 코드에서 numpy를 이용해 속도모델을 읽어들인 후에 matplotlib으로 그립니다. 속도모델을 그리는 부분은 함수로 작성하였는데, 필요에 따라 수정해서 사용하면 되겠습니다.
이전 글에서는 SU 명령어들을 이용해 탄성파 자료처리 결과 확인용 그림을 그리는 방법을 살펴보았습니다. 이번에는 Python의 Matplotlib을 이용하여 그린 그림 예제들을 보겠습니다. 그림은 IPython Processing 모듈을 이용해 그렸으며, 그릴 때 사용한 코드는 github에서 볼 수 있습니다.
속도모델, 구조보정 영상
우선, 다음과 같이 이진파일로부터 2차원 속도모델과 구조보정 결과를 그릴 수 있습니다. 기본적으로 속도모델은 컬러, 구조보정 영상은 흑백으로 그리도록 했지만, 필요에 따라 코드를 수정해서 색상을 바꿀 수 있습니다. 색상을 바꾸고 싶을 경우 imshow 함수의 cmap 인자를 이용하면 됩니다.
%matplotlib inline
from pkprocess import *
import numpy as np
vel = np.fromfile("marm16km.drt", dtype=np.float32)
nx = 576
nz = 188
h = 0.016
vel.shape = (nx, nz)
plot_vel(vel, h)
plot_mig(vel,h)
공통송신원 모음, 스펙트럼
그리고 SU 파일로부터 공통송신원 모음이나 F-X, F-K 스펙트럼을 그릴 수 있습니다. 공통송신원 모음은 Wiggle trace 또는 이미지로 그릴 수 있고, 이미지 색상은 cmap으로 조절 가능합니다.
su = read_su("marm3000.su")
plot_wiggle(su, perc=97)