반응형

     정보

    • 업무명    : 대기 환경 자료 처리 및 가시화 : NetCDF 형식인 대기 온도 자료를 이용한 가시화

    • 작성자    : 이상호

    • 작성일    : 2020-03-31

    • 설   명    :

    • 수정이력 :

     

     내용

    [개요]

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

    • 대기 환경 정보는 다양한 차원의 관측 자료 및 분석 자료로 구성되어 있기 때문에 이용자가 적절한 분석 및 가시화 기술이 요구됩니다.

    • 따라서 오늘 포스팅에서는 NetCDF 형식인 대기 온도 자료를 이용한 가시화를 소개해 드리고자 합니다.

    • 추가로 대기과학 전공자를 위한 IDL를 소개한 링크를 보내드립니다.

     

    [IDL] 아이디엘 대기과학 전공자를 위한 IDL (Interactive Data Language) 소개

    정보 업무명 : 대기과학 전공자를 위한 IDL (Interactive Data Language) 소개 작성자 : 이상호 작성일 : 2020-03-23 설 명 : 수정이력 : 내용 [개요] 안녕하세요? 웹 개발 및 연구 개발을 담당하고 있는 해솔입니..

    shlee1990.tistory.com

     

    [특징]

    • 대기 환경 자료를 이해하기 위해서 자료 처리 및 가시화 기술이 요구되며 이 프로그램은 이러한 목적을 달성하기 위해 고안된 소프트웨어

     

    [기능]

    • 위도, 경도, 대기 온도 자료 읽기

    • 자료 전처리

    • 가시화

    • 동영상 애니메이션

     

    [활용 자료]

    • 자료명 : air.sig995.2014.nc

    • 자료 종류 : 위도, 경도, 대기 온도

    • 확장자 : nc

    • 영역 : 전지구

    • 시간 해상도 : 일 4개 (00, 06, 12, 18)

    • 기간 : 2014년 01월 01일 - 2014년 12월 31일

    • 제공처 : NCAR/NCEP

    air.sig995.2014.z01
    10.00MB
    air.sig995.2014.z02
    10.00MB
    air.sig995.2014.zip
    1.01MB

     

    [사용법]

    • 입력 자료를 동일 디렉터리에 위치

    • 소스 코드를 실행 (idl -e Visualization_Using_Air_Temperature_of_NetCDF_Format)

    • 가시화 결과를 확인

     

    [사용 OS]

    • Windows 10

     

    [사용 언어]

    • IDL v8.5

     

     소스 코드

    • 해당 작업을 하기 위한 컴파일 및 실행 코드는 IDL로 작성되었으며 가시화를 위한 라이브러리는 Coyote's Guide to IDL Programming를 이용하였습니다.

    • 소스 코드는 단계별로 수행하며 상세 설명은 다음과 같습니다.

      • 1 단계는 주 프로그램은 작업 경로 설정, NetCDF 파일 읽기, 변수 전처리하여 메모리상에 저장하고 가시화를 위한 초기 설정합니다.

      • 2 단계는 plots 매핑에 따라 영상 장면 표출하여 이미지 형식으로 저장합니다. 이 과정에서 포스트 스크립트 (PS) 형식에서 PNG로 변환합니다.

     

    [명세]

    • 전역 변수 설정

      • cd를 통해 작업 디렉터리 설정

      • NetCDF 파일 설정 (file)

    cd, 'C:\SYSTEM\PROG\IDL\NetCDF'
    
    file = "INPUT/air.sig995.2014.nc"

     

    • NetCDF 파일 읽기

      • ncdf_varinq를 통해 변수 정보 확인

      • ncdf_attnamencdf_attget를 통해 속성 키와 값 확인

    fileid = ncdf_open(file)  
    file_struct = ncdf_inquire(fileid)
    nvar = file_struct.nvars
    
    for i = 0L, nvar - 1 do begin
    
        varstruct = ncdf_varinq(fileid, i)
        print, i, 'var name : " , varstruct.name
        print, "var type : ", varstruct.datatype
        print, "dims : ", varstruct.dim
    
        for j = 0L, varstruct.natts - 1 do begin
            attname = ncdf_attname(fileid, i, j)
            ncdf_attget, fileid, i, attname, value
            print, attname,'    ',string(value)      
        endfor
    endfor

     

               0var name : " , varstruct.name
    var type : FLOAT
    dims :            0
    units    degrees_north
    actual_range           90.0000      -90.0000
    long_name    Latitude
    standard_name    latitude
    axis    Y
               1var name : " , varstruct.name
    var type : FLOAT
    dims :            1
    units    degrees_east
    long_name    Longitude
    actual_range          0.000000       357.500
    standard_name    longitude
    axis    X
               2var name : " , varstruct.name
    var type : DOUBLE
    dims :            2
    long_name    Time
    delta_t    0000-00-00 06:00:00
    standard_name    time
    axis    T
    units    hours since 1800-01-01 00:00:0.0
    actual_range            1875888.0        1884642.0
               3var name : " , varstruct.name
    var type : FLOAT
    dims :            1           0           2
    long_name    4xDaily Air temperature at sigma level 995
    units    degK
    precision           2
    least_significant_digit           1
    GRIB_id          11
    GRIB_name    TMP
    var_desc    Air temperature
    dataset    NMC Reanalysis
    level_desc    Surface
    statistic    Individual Obs
    parent_stat    Other
    missing_value    -9.96921e+036
    valid_range           185.160       331.160
    actual_range           191.100       322.500

     

    • NetCDF 파일에서 변수 가져오기

      • 1차원 위도 (lon1D), 1차원 경도 (lat1D), 1차원 시간 (time1D), 3차원 대기 온도 (val3D)

      • 시간의 경우 julday를 통해 천문 그라니치 시간을 시간 정보 (년, 월, 일, 시) 변환

     

    V_Name1 = NCDF_VARID(fileid, "lat")
    NCDF_VARGET, fileid, V_Name1, lat1D, COUNT=count, STRIDE=stride, OFFSET=offset
    
    V_Name1 = NCDF_VARID(fileid, "lon")
    NCDF_VARGET, fileid, V_Name1, lon1D, COUNT=count, STRIDE=stride, OFFSET=offset
    
    for i = 0L, N_ELEMENTS(lon1D) - 1 do begin
    if (lon1D(i) gt 180) then lon1D(i) = lon1D(i) - 360
    endfor 
    
    V_Name1 = NCDF_VARID(fileid, "time")
    NCDF_VARGET, fileid, V_Name1, time1D, COUNT=count, STRIDE=stride, OFFSET=offset
    
    dtJulday = julday(01, 01, 1800, time1D, 0, 0)
    sDateYmdH = STRING(dtJulday, format="(C(CYI4.4, CMOI2.2, CDI2.2, CHI2.2))")
    
    V_Name1 = NCDF_VARID(fileid, "air")
    NCDF_VARGET, fileid, V_Name1, val3D, COUNT=count, STRIDE=stride, OFFSET=offset
    
    ncdf_close, fileid

     

    • 요약 통계량 확인

      • 최소값 (min), 평균값 (mean), 최대값 (max) 계산

      • help를 통해 자료형 및 배열 정보 확인

    print, min(time1D, /nan), mean(time1D, /nan), max(time1D, /nan)
    print, min(lon1D, /nan), mean(lon1D, /nan), max(lon1D, /nan)
    print, min(lat1D, /nan), mean(lat1D, /nan), max(lat1D, /nan)
    print, min(val3D, /nan), mean(val3D, /nan), max(val3D, /nan)
    
    help, time1D, lon1D, lon1D, val3D

     

     

    • 가시화

      • 데이터 세트에서 정보는 여전히 숨겨져 있기 때문에 가시화 필요

      • 가시화는 일반적인 정적 탐색 데이터 분석에서 웹 브라우저의 동적 대화식 데이터 시각화에 이르기까지 다양함

     

    • 대기 온도를 위한 설정 및 가시화

      • 관심 영역 (ROI)와 중심 위/경도 (cnLon, cnLat) 설정

      • 시간 배열에 대해 반복문 수행

      • 이미지 저장 파일명 (psName) 및 제목명 (mainName)

      • fnMakePsPlot를 통해 이미지 저장

    ROI = [-90, 90, -180, 180]
    cnLon = 0
    cnLat = 0
    
    val2D = fltarr(dim[0], dim[1])
    
    for iCount = 1, dim[2] - 1 do begin
    
        val2D[*, *] = val3D[*, *, iCount]
    
        psName = "Img01_" + sDateYmdH[iCount]
        mainName = "NCAR/NCEP Air Temperature : " + sDateYmdH[iCount]
    
        fnMakePsPlot, lon1D, lat1D, val2D, dim, cnLat, cnLon, ROI, psName, mainName, 200, 350, 25, 33
    
    endfor

     

     

    • 동영상 애니메이션 설정

      • 반복문 수행한 이후 spawn를 통해 1초마다 동영상 애니메이션 생성

    com = "convert -loop 0 -delay 100 "+ "./FIG/*.png" + " " + "./GIF/Img01.gif"
    spawn, /hide,  com

     

     

    • 사용자 편의성 함수 정의

      • 전달 인자

        • 1차원 위도 (lon1D), 1차원 경도 (lat1D), 2차원 값 (val2D), 배열 정보 (dim), 중심 위도 (cnLat), 중심 경도 (cnLon), 관심 영역 (ROI), 이미지 저장 파일명 (psName), 제목명 (mainName), 최소값 (zmin), 최대값 (zmax), 등고선 간격 (interval), 컬러 테이블 (color_table)

      • 기능

        • plots를 통해 위/경도에 따른 값 매핑

        • 포스트 스크립트 (PS)를 PNG로 변환

    ;====================================================================
    ; Subroutine : Function Make Postscript to Png Graph
    ;====================================================================
    pro fnMakePsPlot, lon1D, lat1D, val2D, dim, cnLat, cnLon, ROI, psName, mainName, zmin, zmax, interval, color_table
    
        set_plot, "ps"
      
        device, filename = psName + ".ps", decomposed = 0, bits = 8, /color, xsize = 19, ysize = 10, /inches, font_size = 13, /Helvetica
      
        !p.font = 0 & !p.charsize = 2.0 & !p.charthick = 1.6  & !p.multi = [0,1,1] & !p.background = 255
      
        xvert = [0.1, 0.1, -0.1, -0.1 ,0.1]
        yvert = [-0.1, 0.1, 0.1, -0.1, -0.1]
      
        usersym, xvert, yvert, /fill
      
        start_color = 0 & end_color = 255 & colorn = end_color - start_color + 1
      
        cgloadct, color_table
      
        latmin = ROI(0) & latmax= ROI(1) & lonmin = ROI(2) & lonmax= ROI(3)
      
        cgMAP_SET, cnLat, cnLon, /CYLINDRICAL $
          , limit = [latmin, lonmin, latmax, lonmax] $
          , position = [0.05, 0.0, 0.85, 0.90], /noborder, /ISOTROPIC
      
        for i = 0L, dim[0] - 1 do begin
          for j = 0L, dim[1] - 1 do begin
      
            nLon = lon1D[i]
            nLat = lat1D[j]
            nVal = val2D[i, j]
      
            if (lonmin gt nLon or nLon gt lonmax or finite(nLon, /nan) eq 1) then continue
            if (latmin gt nLat or nLat gt latmax or finite(nLat, /nan) eq 1) then continue
            if (finite(nVal, /nan) eq 1) then continue
      
            plots, nLon, nLat, psym = 8, symsize = 14, color = BYTSCL(nVal, zmin, zmax)
      
          endfor
        endfor
      
        cgColorbar, NColors = 255, BOTTOM = 1 $
          , Divisions = 5, COLOR = "black" $
          , Position = [0.1, 0.90, 0.8, 0.94] $
          , Range = [zmin, zmax] $
          , CHARSIZE = 1.5,CHARthick = 2 $
          , VERTICAL = 1, RIGHT = 1, Format = "(i3)"
      
          cgLoadct, 14
      
          contour, val2D, lon1D, lat1D, /overplot, C_THICK = 2 $
            , LEVELS = zmin + findgen(10) * interval $
            , C_LABELS = zmin + findgen(10) * interval $
            , C_CHARSIZE = 1.5, C_CHARTHICK = 2 $
            , C_COLORS = BYTSCL(zmin + findgen(10) * interval, zmin, zmax)
      
        cgMAP_CONTINENTS, /coast, /countries, COLOR = "black"
    ;                      , /hires
      
        lats = [-90:90:30]
        lons = [-180:360:60]
      
        lats_names = strarr(n_elements(lats))
        lons_names = strarr(n_elements(lons))
      
        for i = 0L, n_elements(lats) - 1 do begin
          if (lats[i] gt 0) then begin
            lats_names[i] = textoidl(string(lats[i]) + "\circN")
          endif else if (lats[i] eq 0) then begin
            lats_names[i] = textoidl(string(lats[i]) + "\circ")
          endif else begin
            lats_names[i] = textoidl(string(-lats[i]) + "\circS")
          endelse
        endfor
      
        for i = 0L,n_elements(lons) - 1  do begin
          if (lons[i] gt 0) then begin
            lons_names[i] = textoidl(string(lons[i]) + "\circE")
          endif else if (lons[i] eq 0) then begin
            lons_names[i] = textoidl(string(lons[i]) + "\circ")
          endif else begin
            lons_names[i] = textoidl(string(-lons[i]) + "\circW")
          endelse
        endfor
        
        cgMap_grid, color = "black", charsize = 1.8, thick = 2.5, lats = lats,  latnames = lats_names, lons = lons, lonnames = lons_names $
          , linestyle = 1, bthick = 300, /box_axes, /no_grid
      
        cgText, 0.45, 0.95, mainName, /normal, charsize = 2, CHARTHICK = 2, color = "black", alignment = 0.5
      
        device, /close_file
      
        com = "convert -flatten -background white " + psName + ".ps" + " " + "./FIG/" + file_basename(psName, ".ps") + ".png"
        spawn, /hide, com
      
        file_delete, psName + ".ps"
      
        return
    
    end

     

    [전체] 

     

     참고 문헌

    [논문]

    • 없음

    [보고서]

    • 없음

    [URL]

    • 없음

     

     문의사항

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

    • sangho.lee.1990@gmail.com

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

    • saimang0804@gmail.com
    반응형
    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기