IDL/Data Type & Format

GRIB 포맷의 파일을 읽고 데이터를 표출하기 [1]

이상우_idl 2018. 6. 29. 11:00
728x90
반응형

오늘은 GRIB라는 포맷의 파일을 IDL에서 읽는 방법에 관하여 알아보겠습니다. GRIB는 GRIdded Binary의 약어이며, 주로 기상/대기/해양 분야에서 많이 사용되는 포맷이기도 합니다. 이 포맷은 GRIB1, GRIB2 두 종류가 있는데, 2018년 현재 GRIB2가 WMO(국제기상기구)에서 표준으로 지정한 기상 데이터의 포맷인 것으로 알고 있습니다. 어쨌든 GRIB 포맷의 파일을 읽고 쓰는 기능은 IDL에서는 8.1 버전에서부터 공식적으로 지원되어오고 있습니다. 사실 8.1 버전 이전에는 IDL_GRIB라는 별도의 외부 라이브러리를 따로 받아서 설치해야 했었는데(마치 IDL Astro나 Coyote 라이브러리처럼), 지금은 IDL 자체적으로 GRIB 포맷 관련 기능을 내장하고 있으므로 그냥 이 기능을 사용하면 됩니다. IDL의 GRIB 포맷 관련 루틴들에 대한 일람은 IDL 도움말에서 다음과 같은 섹션에서 확인이 가능합니다.


Routines (by Topic) -> Input/Output -> GRIB Formats -> GRIB Routines


물론 IDL 도움말에서 grib로 검색해서 바로 이 페이지로 들어갈 수도 있습니다. 어쨌든 이 섹션 페이지를 보면 GRIB 관련 루틴들이 상당히 많다는 것을 알 수 있습니다. 그래서 나에게 GRIB 포맷의 파일이 주어진 상태라고 할 때, 구체적으로 어떤 루틴을 어떻게 사용해야 할것인지를 가늠하기가 다소 힘들 수도 있습니다. 이러한 점은 GRIB 뿐만 아니라 HDF, CDF, NetCDF 포맷 관련 루틴들에 관한 내용을 봐도 비슷합니다. 따라서 여기서는 예제 GRIB 파일을 대상으로 하여 그 안에 포함되어 있는 데이터를 추출하는 과정을 한번 살펴보기로 하겠습니다. 이 과정에서는 당연히 GRIB 관련 루틴들 중 몇 가지를 사용하게 될 것입니다. 물론 제가 제시하는 과정은 완벽한 표준이라기보다는 하나의 예제에 불과하기 때문에, GRIB 포맷의 파일을 읽는 작업에 있어서는 제가 오늘 다루지 않는 다른 GRIB 관련 루틴들이 필요할 수도 있을 수 있음을 미리 언급해 둡니다.


오늘 예제로 사용할 파일은 기상청에서 기상자료개방포털을 통하여 제공하고 있는 LDAPS(국지예보모델) 자료 파일입니다. 이 자료 파일은 2018년 현재 GRIB2 포맷으로 제공되고 있습니다. 다만 이 파일이 크기가 그리 작은 편은 아니어서(약 88MB 정도) 이 게시물에 바로 첨부하지는 못하고 링크로 대체합니다. 이 링크를 통해서 받으시기 바랍니다. 이 예제용 파일은 파일명에서 알 수 있듯이 날짜 및 시간은 2016년 7월 26일 00시에 해당됩니다. 아시는 분들은 아시겠지만 만약 특정한 날짜 및 시간에 해당되는 파일(들)을 받고자 할 경우에는 기상자료개방포털 웹페이지에서 직접 받아야 합니다. 그리고 이 파일의 확장자가 gb2로 되어 있는 것은 GRIB2 포맷이기 때문입니다. LDAPS 자료에 관한 제원 및 기술적인 내용은 같은 웹페이지에서 관련 문서를 받을 수 있으므로 이 내요을 참조하시면 됩니다. 여기서는 파일을 읽는 과정에만 집중하도록 하겠습니다.


그러면 본격적으로 시작해보겠습니다. 이 파일을 읽는 작업에 있어서는 가장 먼저 이 파일 내에 수록된 레코드(Record)의 갯수를 확인하는 것이 필요합니다. 레코드는 그냥 이 파일 내에 포함되어 있는 여러 종류의 데이터들을 지칭한다고 보면 되는데, GRIB 포맷에서는 레코드라고도 하고 메시지(Message)라고도 합니다. 두 용어는 사실상 동일한 의미라고 봐도 무방합니다. 어쨌든 레코드의 갯수를 직접 확인하려면 다음과 같이 파일에 대하여 GRIB_COUNT 함수를 사용하면 됩니다.


file = 'data/DAPS/l015_v070_erlo_unis_h000.2016072600.gb2'

nr = GRIB_COUNT(file)

PRINT, nr


여기서 출력된 nr이라는 변수의 값은 136으로 나옵니다. 즉 136개의 레코드들이 수록되어 있다는 의미입니다. 이제는 이 136개의 레코드들이 각각 어떤 종류의 데이터인가를 확인하는 것이 필요합니다. 이를 위해서는 다음과 같이 GRIB_LIST 프로시저를 사용하여 구체적인 레코드 목록을 확인할 수 있습니다.


GRIB_LIST, file


이와 같은 형태로 GRIB_LIST 명령을 사용하면 레코드의 목록을 보여줍니다. 다음은 이렇게 출력된 레코드 목록의 앞부분 일부입니다. 실제로는 총 136줄에 걸쳐 목록이 출력됩니다.


  1     unknown     DOUBLEARRAY[470162]

  2     unknown     DOUBLEARRAY[470162]

  3     unknown     DOUBLEARRAY[470162]

  4     unknown     DOUBLEARRAY[470162]

  5     unknown     DOUBLEARRAY[470162]

  6     unknown     DOUBLEARRAY[470162]

  7     unknown     DOUBLEARRAY[470162]

  8     ncpcp       DOUBLEARRAY[470162]

  9     snol        DOUBLEARRAY[470162]

 10     lsprate     DOUBLEARRAY[470162]

 11     lssrate     DOUBLEARRAY[470162]

 12     unknown     DOUBLEARRAY[470162]

 13     unknown     DOUBLEARRAY[470162]

 14     unknown     DOUBLEARRAY[470162]

 15     10u         DOUBLEARRAY[470162]

 16     10v         DOUBLEARRAY[470162]

 17     unknown     DOUBLEARRAY[470162]

 18     unknown     DOUBLEARRAY[470162]

 19     unknown     DOUBLEARRAY[470162]

 20     lhtfl       DOUBLEARRAY[470162]

 21     2t          DOUBLEARRAY[470162]

 22     tmin        DOUBLEARRAY[470162]

 23     tmax        DOUBLEARRAY[470162]

 24     q           DOUBLEARRAY[470162]


이와 같이 세 개의 컬럼으로 구성된 목록이 출력되는데, 여기서 각 컬럼은 레코드 번호, 레코드 이름, 데이터 형태에 해당됩니다. 만약 이러한 레코드 목록을 그냥 보기만 하는 것이 아니라 배열의 형태로 따로 담고자 한다면, 다음과 같이 OUTPUT 키워드를 사용하는 것도 가능합니다.


GRIB_LIST, file, OUTPUT=rlist

HELP, rlist


이렇게 하면 3x136의 구조를 갖는 rlist라는 문자형 배열로 얻어집니다. 어떻게 하든 나머지 과정에는 별 영향이 없으므로 이런 것도 가능하다 정도로 생각해두시면 됩니다. 그러면 이제는 위와 같은 총 136개의 레코드들 중 어느 레코드를 추출할 것인가를 결정하여 그 레코드에 해당되는 데이터를 추출하는 작업이 필요합니다. 여기서는 번호가 21인 "2t"라는 레코드의 데이터(아마도 지상 2m 높이에서의 기온 데이터인 것으로 알고 있습니다)를 추출해보겠습니다. 데이터 추출을 위해서는 다음과 같이 GRIB_GETDATA 함수를 사용하면 됩니다. 이 함수를 사용할 때에는 파일명과 레코드 번호를 인수로 주면 됩니다. 그리고 추출된 데이터에 대해서는 data라는 이름을 부여하였습니다. 이렇게 추출된 data라는 항목이 어떤 형태인지를 확인하기 위하여 HELP 명령도 사용하였습니다.


rnum = 21; record number (2m temperature)

data = GRIB_GETDATA(file, rnum)

HELP, data


그런데 HELP로 확인해본 data에 관한 정보를 보면 좀 특이합니다. 출력된 내용은 실제로 다음과 같습니다.


DATA            ORDEREDHASH  <ID=312660  NELEMENTS=204>


사실 그냥 바로 배열이 얻어질 것으로 기대할 수도 있는데, 실제로 얻어진 것은 이와 같이 "ORDEREDHASH"라는 형태의 데이터입니다.이것은 Ordered Hash라는 자료형에 해당되는데, 기본적으로 키(Key)와 값(Value)의 쌍으로 구성된 데이터를 담는 자료형인 Hash와 유사합니다. 다만 그냥 Hash는 데이터를 삽입한 순서에 관한 정보는 전혀 포함하지 않지만, Ordered Hash는 이러한 순서에 관한 정보도 함께 포함되는 형태라는 차이점만 있습니다. 그리고 위의 내용에서 204라는 숫자가 보이는데, 이 숫자는 data라는 Hash 형태의 데이터 내부에 몇 개의 세부 항목들이 포함되어 있는가를 나타내는 값입니다. 결국은 현재 우리가 다루고 있는 GRIB2 포맷의 파일의 경우에는 총 136개의 레코드들이 수록되어 있는데, 하나의 레코드 내부에도 총 204개의 세부 정보(일종의 메타 정보)들이 포함되어 있다는 것을 알 수 있습니다. 그러면 각 레코드마다 포함하고 있는 204개의 세부 정보들이 구체적으로 무엇인가를 확인할 필요가 있습니다. 이 과정은 다음과 같이 해볼 수 있습니다.


n = data.Count()

keys = data.Keys()

values = data.Values()

PRINT, n

HELP, keys, values


사실 Hash라는 자료형이 익숙하지 않은 유저에게는 좀 당황스러울 수도 있는데, 그냥 위와 같이 Hash 형태의 데이터로부터 구체적인 정보들을 하나하나 뽑아낸다고 보면 됩니다. 일단 변수 n의 값은 204가 나옵니다. 그리고 keys 및 values는 각각 리스트(List)라는 자료형의 데이터로 얻어졌음을 알 수 있습니다. 그런데 여기서 또 리스트(List)라는 자료형이 등장하는데, 일단 이 자료형에 관한 일반적 사항은 지금의 과정에서는 크게 중요하지는 않으므로 신경쓰지 않겠습니다. 혹시라도 리스트(List) 및 해쉬(Hash) 자료형에 관한 기본적인 내용이 궁금하신 분들은 제가 예전에 올렸던 관련 게시물들(리스트1, 리스트2, 해쉬)을 참조하시면 됩니다. 어쨌든 현 단계에서는 keys와 values의 내용이 구체적으로 무엇인지를 보는 것이 중요하므로, 다음과 같은 반복형 구문을 사용하여 총 204개의 keys와 values의 내용을 하나하나 출력해봅시다.


FOR j = 0, n-1 DO BEGIN

  PRINT, j, '  ', keys[j]

  HELP, values[j]

ENDFOR


이렇게 하면 당연히 204개의 정보들이 모두 출력되는데 이 출력 내용 중에서 일부만 보면 다음과 같습니다.


      30  dataDate

<expression>    LONG64    =               20160726


이 항목은 날짜 정보에 해당됩니다. 여기서 "dataDate"는 키(key)의 명칭입니다. 이러한 키 명칭이 중요합니다. 이러한 키 명칭으로 인덱싱을 해서 실제 데이터를 뽑아내야 하기 때문입니다. 또한 다음과 같은 항목도 있습니다.


     153  name

<expression>    STRING    = '2 metre temperature'


이 항목은 데이터의 명칭에 해당됩니다. 현재의 레코드가 어떤 종류의 데이터인지 이 정보를 통해서 알 수 있습니다. 키 명칭인 "name"이 중요합니다. 그리고 다음과 같은 항목들도 있습니다.


      59  Nx

<expression>    LONG64    =                    602

      60  Ny

<expression>    LONG64    =                    781


이 항목들은 실제 데이터 배열의 가로 및 세로 크기를 나타냅니다. 따라서 602x781의 격자 구조를 갖는 2차원 배열의 형태로 실제 데이터가 존재한다는 것을 알 수 있습니다. 키 명칭인 "Nx", "Ny" 역시 중요합니다.


따라서 총 204개의 항목들 중에는 실제로 유저에게 중요한 것들도 있고 그렇지 않은 것들도 있습니다. 어떤 항목이 중요한가에 대한 판단은 유저가 의도하는 작업의 구체적인 내용에 따라 다를 수 밖에 없습니다. 일단 여기서 저는 "2 meter temperature"라고 하는 데이터를 추출한 다음 이 데이터를 지도상에 표출하는 작업을 하려고 합니다. 즉 GRIB2 포맷의 파일로부터 특정 데이터를 뽑아내고, 바탕이 될 지도(Map)를 표출하고, 그 위에 2차원 데이터의 형태로 중첩하는 일련의 작업이 될 예정입니다. 이러한 작업을 진행하기 위해서는 앞서 확인한 204개의 세부 정보들 중 필요한 것들이 더 있습니다. 또한 이러한 정보들을 추출하여 어떤 방식으로 표출 작업에 활용할 것인가에 대해서도 구체적인 플랜이 필요합니다. 오늘은 일단 여기까지 말씀을 드리기로 하고, 나머지 과정에 대해서는 곧 이어지는 게시물에서 다루도록 하겠습니다.

반응형