IDL/Programming

Yale Bright Star Catalog 데이터 읽기 (개선된 방법)

이상우_IDL 2025. 4. 15. 15:26
728x90

최근에 Yale Bright Star Catalog(예일 밝은 별 목록, YBSC) 데이터를 바이너리 파일(Binary File)의 형태로 입수하여 그 파일을 읽고 관련 표출을 해보는 방법을 총 4회에 걸쳐서 연재한 바 있습니다. 그래서 제가 전달하고자 했던 모든 내용들은 이미 다 소개가 된 상태입니다. 다만 이번에 또 YBSC 데이터 읽기라는 타이틀로 또 다른 게시물을 올리게 된 이유는, 해당 바이너리 파일을 IDL에서 읽고 그 데이터를 배열로 가져오는데 있어서 이미 소개된 READ_BINARY 함수를 주로 사용하는 방식 외에도 또 다른 방식들이 있다는 것을 소개할 필요가 있다는 판단 때문입니다. 그래서 오늘은 그 방법들을 자세히 소개해보기로 하겠습니다.

 

방금 언급했듯이 기존에 소개했던 방식은 주로 READ_BINARY 함수를 사용하는 방식이었습니다. 하지만 IDL에서 바이너리 파일을 읽는데 있어서는 OPENR, READU 명령들을 사용하는 방식도 존재합니다. 이러한 방식은 예전에 관련 게시물을 통하여 대략적으로 소개를 한 적이 있습니다. 그러면 YBSC 바이너리 파일을 이러한 방식으로 읽어보도록 하겠습니다. 이 바이너리 파일에 수록된 데이터의 구조에 관해서는 이미 관련 게시물에서 소개한 바 있으므로 그 자세한 내용은 여기서는 생략하고 바로 읽기 과정으로 진행하기로 합니다. 먼저 파일을 명시하고 헤더 부분을 읽기 위한 배열을 다음과 같이 정의합니다.

 

file = 'BSC5'

header = LONARR(7)

 

그리고 하나의 레코드에 대하여 각 항목 데이터를 읽기 위한 변수들을 항목별 자료형에 맞게 다음과 같이 정의합니다.

 

cnum = 0.0
ra_rad = 0.0d
dec_rad = 0.0d
type = BYTARR(2)
vmag = 0
pm_ra = 0.0
pm_dec = 0.0

 

그 다음에는 배열로 얻고자 하는 항목들 각각에 대한 배열을 역시 항목별 자료형에 맞게 다음과 같이 정의합니다. 각 레코드 내에는 7종의 항목들이 존재하지만 여기서는 5종의 항목들에 대해서만 배열로 가져오기로 합니다.

 

n = 9110
cnums = INTARR(n)
ra_degs = DBLARR(n)
dec_degs = DBLARR(n)
types = STRARR(n)
vmags = FLTARR(n)

 

이제 다음은 OPENR 명령으로 파일로 통하는 통로를 열어두고 READU 명령을 사용하여 순서대로 데이터를 읽는 과정입니다. 여기서는 헤더 부분은 먼저 읽어서 넘기고 이후의 9110개의 레코드들을 순차적으로 읽으면서 각 항목별 값을 배열에 담는 과정이 반복형 작업으로 진행됩니다.

 

OPENR, lun, file, /GET_LUN
READU, lun, header
FOR i = 0, 9110-1 DO BEGIN
  READU, lun, cnum, ra_rad, dec_rad, type, vmag, pm_ra, pm_dec
  cnums[i] = FIX(cnum)
  ra_degs[i] = ra_rad*!radeg
  dec_degs[i] = dec_rad*!radeg
  types[i] = STRING(type)
  vmags[i] = vmag/100.
ENDFOR
FREE_LUN, lun
HELP, cnums, ra_degs, dec_degs, types, vmags

 

이와 같은 과정이 실행되고 HELP에 의하여 출력된 내용을 보면 다음과 같습니다.

 

CNUMS           INT       = Array[9110]
RA_DEGS         DOUBLE    = Array[9110]
DEC_DEGS        DOUBLE    = Array[9110]
TYPES           STRING    = Array[9110]
VMAGS           FLOAT     = Array[9110]

 

이와 같이 우리가 얻고자 했던 5종의 항목별 배열들에 대한 기본 정보가 출력되며 각각 9110개의 값들로 구성된 배열임을 알 수 있습니다. 올바르게 데이터가 획득되었는지 확인하기 위하여 다음과 같이 각 배열의 처음 10개의 값들만 출력하도록 해봅시다.

 

FOR i = 0, 9 DO $
  PRINT, cnums[i], ra_degs[i], dec_degs[i], types[i], vmags[i], $
  FORMAT='(I4.4, 2X, F0, 2X, F0, 2X, A0, 2X, F5.2)'

 

출력된 내용은 다음과 같습니다. 이 내용을 보면 5종의 배열들이 올바르게 획득되었음을 알 수 있습니다.

 

0001  1.291250  45.229164  A1   6.70
0002  1.265833  -0.503056  G9   6.29
0003  1.333750  -5.707500  K0   4.61
0004  1.425000  13.396110  G5   5.51
0005  1.566667  58.436663  G5   5.96
0006  1.579167  -49.074997  G1   5.70
0007  1.610417  64.196108  B9   5.59
0008  1.653333  29.021387  K0   6.13
0009  1.708750  -23.107499  A7   6.18
0010  1.825833  -17.386388  A6   6.19

 

이와 같이 OPENR, READU 명령들을 사용하여 읽는 것도 가능합니다. 그리고 이전에 소개했던 READ_BINARY 함수를 사용하는 방식과 비교하면 오늘 소개된 방식이 더 효율적입니다. 그 이유는 소요시간이 대폭 단축되기 때문입니다. 실제로 제가 테스트해본 바로는 전자의 방법은 약 66초가 소요된 반면 오늘 소개한 방법은 불과 0.9초 정도가 소요되었습니다. 따라서 효율성 측면에서 본다면 오늘 소개된 방법이 훨씬 더 효율적입니다. 이와 같이 두 방법 사이에 소요시간이 많이 차이가 나는 이유는 대략 두가지 정도로 요약할 수 있습니다.

 

(1) READ_BINARY 함수의 경우는 매번 사용할 때마다 내부적으로 파일에 대한 OPEN 및 CLOSE를 수행하기 때문에 기존의 방식에서는 이러한 작업을 총 9110회에 걸쳐서 반복하므로 여기서 시간을 많이 잡아먹는다.

(2) 배열을 정의하고 값을 채워나가는데 있어서 처음에 !null로 정의하고 arr = [arr, value]와 같은 방식으로 값을 계속 붙여가면서(append) 그 크기를 늘려가는 방식은 배열을 매번 새롭게 생성하는 것과 마찬가지이므로 역시 시간이 걸린다.

 

제가 예전에 관련 게시물에서도 언급을 한 바 있듯이 READ_BINARY를 사용하는 것이 효율적인 경우가 있고 오늘처럼 OPENR, READU를 사용하는 것이 효율적인 경우가 있습니다. 이번에 다루고 있는 YBSC 바이너리 파일의 경우는 후자에 해당된다고 보면 될 것 같습니다. 그리고 배열을 처음에 !null로 정의했다가 계속 살을 붙여가는 방식은 원래는 배열의 전체 갯수에 대한 확신이 없는 경우에 사용하는 방법이긴 합니다. 이번 데이터처럼 9110개 이렇게 확실한 경우에는 오늘 소개된 방식과 같이 배열 자체를 처음부터 9110개의 값들로 구성된 형태로 정의하고 작업하는 것이 더 낫다고 보면 됩니다.

 

그리고 앞서 소개된 OPENR, READU를 사용하는 방식이라는 점은 동일하지만 구조체(Structure)의 개념을 사용하는 방식도 있습니다. 그 과정은 다음과 같습니다.

 

file = 'BSC5'

header = LONARR(7)
one_rec = {cnum:0.0, ra_rad:0.0d, dec_rad:0.0d, type:BYTARR(2), vmag:0, pm_ra:0.0, pm_dec:0.0}
bsc5 = REPLICATE(one_rec, 9110)
OPENR, lun, file, /GET_LUN
READU, lun, header
READU, lun, bsc5
FREE_LUN, lun
cnums = FIX(bsc5.cnum)
ra_degs = bsc5.ra_rad*!radeg
dec_degs = bsc5.dec_rad*!radeg
types = STRING(bsc5.type)
vmags = bsc5.vmag/100.
HELP, cnums, ra_degs, dec_degs, types, vmags

 

여기서는 하나의 레코드에 해당되는 구조체(Structure)를 one_rec이라는 이름으로 정의한 다음 이러한 형태의 구조체들이 총 9110개가 모여서 구성되는 일종의 구조체 배열인 bsc5를 정의하였습니다. 그리고 바이너리 파일에 접근하여 데이터를 읽는데 있어서는 헤더 부분을 읽은 이후에 바로 bsc5를 통하여 9110개의 레코드들을 통째로 읽어옵니다. 다만 우리가 원하는 5종의 항목별 배열을 얻기 위해서는 구조체 배열 bsc5로부터 각 필드대 대하여 필요한 처리를 하는 것이 필요합니다. 최종 결과는 당연히 앞선 예제와 동일합니다. 그리고 중요한 것이 속도 측면에서 보면 이 방식이 가장 효율적이라는 것입니다. 실제로 제가 테스트한 바로는 이 방식의 경우 소요시간이 불과 0.003초였기 때문입니다.

 

따라서 BSC5 바이너리 파일을 읽는데 있어서는 이전의 게시물에서 소개했던 READ_BINARY 함수를 사용하는 방법보다는 오늘 소개한 OPENR, READU를 사용하는 방법이 더 효율적이라는 것을 확인할 수 있습니다. 다만 우리가 과학기술 분야에서 일반적으로 얻게 되는 바이너리 파일들의 경우 내부에 데이터가 수록된 방식과 구조가 매우 다양합니다. 따라서 이러한 파일을 입수하여 읽어야 할 경우에는 그 특성에 맞춰서 가장 효율적인 방법을 택하는 것이 매우 중요하다는 점을 참조해두시면 좋을 것 같습니다.

 

 

이 글이 도움이 되었다면 게시물에 대하여 공감 버튼(하트 모양) 클릭 및 블로그 구독도 해주시면 더 큰 힘이 됩니다. 감사합니다.

LIST