수치모델:단중기모델:한국형수치예보모델_kim
차이
문서의 선택한 두 판 사이의 차이를 보여줍니다.
| 양쪽 이전 판이전 판다음 판 | 이전 판 | ||
| 수치모델:단중기모델:한국형수치예보모델_kim [2024/05/22 02:30] – kaishoo | 수치모델:단중기모델:한국형수치예보모델_kim [2026/08/19 09:23] (현재) – [1. 개요] 118.235.66.82 | ||
|---|---|---|---|
| 줄 1: | 줄 1: | ||
| ====== | ====== | ||
| - | ===== 1.1. 개요 ===== | + | [[수치모델: |
| - | KIM은 육면체구 격자 기반의 전지구모델로 분광요소법 기반 수치계의 비정역학 코어와 | + | ===== 1. 개용 |
| + | ==== 1.1. 수치예보 설명 ==== | ||
| + | 수치예보(Numerical Weather Prediction : NWP)란 대기현상의 역학 및 물리적 원리에 대한 지배방정식들을 컴퓨터를 활용하여 연속적으로 수치적분함으로써 현재의 대기상태를 분석하고 나아가 미래의 대기상태를 정략적으로 예측하는 일련의 과정입니다. | ||
| + | |||
| + | 수치예보의 수행과정은 기상관측자료 전처리 → 자료동화 → 수치예보모델 → 후처리 → 검증 순으로 진행됩니다. | ||
| + | {{절차.png? | ||
| + | |||
| + | |||
| + | === 1.1.1. 기상관측자료 전처리 === | ||
| + | 기상관측자료 전처리 수치예보모델에 입력할 관측자료를 준비하는 과정으로 전세계에서 관측한 다양한 종류의 관측자료를 수집하여 해독하고(자료수집 및 해독 과정) 수집된 자료 중 품질이 낮은 관측자료를 제거하는 과정(품질검사 과정)으로 구성되어 있습니다. 관측전처리 과정을 통해 관측자료에 포함된 오차를 평가하고 편차를 제거하는 과정은 자료동화 및 수치예보모델의 성능에 중요한 역할을 합니다. | ||
| + | {{전처리 절차.png? | ||
| + | {{자료 수집.png? | ||
| + | |||
| + | === 1.1.2. 자료동화 === | ||
| + | 모델은 항상 오차를 가지게 마련이며, | ||
| + | ^전통적인 자료동화^현대의 자료동화^ | ||
| + | |{{전통적인 자료동화.png? | ||
| + | {{변분법.png? | ||
| + | |||
| + | |||
| + | === 1.1.3. 수치예보모델 === | ||
| + | 수치예보모델을 이용해 대기의 상태 및 운동을 설명하는 대기방정식을 풀어 미래의 날씨를 계산하는 과정입니다. 대기방정식은 너무 복잡하여 정확한 해를 직접적으로 구할 수 없기 때문에, 수치해석적인 방법으로 근사적인 해를 구하게 됩니다. 수치예보모델은 대기의 큰 흐름이나 운동을 정의하는 역학과정과 작은 규모의 물리적인 현상들을 정의하는 물리과정으로 구성되어 있습니다. | ||
| + | |||
| + | ^역학과정^물리과정^ | ||
| + | |지구를 수평· 연직 방향의 격자로 나누어 날씨의 변화를 지배하는 편미분 형태의 방정식계를 계산합니다. 따라서 격자 모양이나 간격, 방정식계를 미적분하는 방식 등에 따라 다양한 형태로 표현될 수 있으며, 이에 따라 수치모델 결과도 다르게 나타납니다.|수치모델의 역학과정에서 명시적으로 표현하지 못하는 모델 격자보다 작은 규모(아격자 규모)의 현상들은 수치모델의 물리과정에서 계산됩니다. 즉, 수치모델의 물리과정에서는 대기복사, | ||
| + | |{{격자체계.png? | ||
| + | |||
| + | ==수치예보모델 유형== | ||
| + | ^전지구모델| * 지구 전체를 영역으로 하는 모델 | ||
| + | ^제한지역모델 \\ (지역모델 또는 국지모델)| * 특정한 지역(예: 아시아, 동아시아, | ||
| + | ^초단기모델| * 12시간 이내 한반도 영역에서 일어난 현상을 아주 상세히 예측하기 위한 모델 \\ * 빠른 | ||
| + | ^기후모델| * 수십 년 이상의 장기간에 대한 기후변화를 예측하기 위한 모델 \\ * 장기간 예측을 해야 하는 만큼 저해상도 모델이 됨| | ||
| + | ^앙상블모델| * 같은 모델을 초기조건을 달리하여 여러 개 돌리거나 다른 모델을 하나의 세트로 묶어 돌림으로써 미래상태에 대한 확률적인 정보를 제공하는 모델 체계를 말함 \\ * 일반적으로 앙상블모델의 성능이 앙상블모델을 구성하는 개개 단일모델의 성능보다 우수한 것으로 알려져 있음| | ||
| + | ^통계모델| * 모델에서 나온 결과들을 통계적 기법을 이용해 한번 더 보정할 목적으로 수행되는 모델 \\ * 많은 과거 데이터를 모아 장기간에 걸쳐 패턴(관계식)을 분석하고 이를 현재 예측에 적용 (MOS, 기계학습 등)| | ||
| + | ^응용모델| * 특수한 목적으로 사용되는 모델 \\ * 황사모델, | ||
| + | |||
| + | === 1.1.4. 후처리 === | ||
| + | 수치모델이 생산한 디지털자료를 가시화하여 일기도와 가이던스를 생산하는 가시화 과정과 모델의 오차를 통계적으로 보정해 더 정확하고 상세한 예측결과를 제공하는 통계과정 등이 있습니다. | ||
| + | ^가시화^예보가이던스^ | ||
| + | |수치예보모델 산출 결과는 다양한 변수가 숫자 형태로 예측시간별로 저장되어 있어 바로 이해하기 어렵습니다. 가시화는 이러한 숫자 형태의 자료를 보기 쉽고 이해하기 쉽게 그림이나 표 등의 시각적 형태로 표현하는 과정입니다.|수치예보모델로 예측된 자료를 과학적으로 처리하여 수요자(예보관)가 필요로 하는 정보로 가공한 결과물입니다. 수치예보모델은 다양한 시간, 공간해상도를 가지고 수행되지만 최종적으로는 동네예보(5km×5km간격, | ||
| + | |{{가시화2.png? | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | === 1.1.5. 검증 | ||
| + | 수치예보모델이 가지는 오차가 얼마나 되는지 수치로 평가하는 과정이다. | ||
| + | 모델의 결과를 관측자료를 기준으로 검증하는 것을 관측검증이라 하며, 자료동화를 통해 생산된 고품질의 분석장을 기준으로 모델을 검증하는 것을 분석검증이라 한다. | ||
| + | |||
| + | ^관측검증^분석검증^ | ||
| + | |세계기상기구(WMO)에서 매년 업데이트해서 제공하는 약 700여개의 고층관측(라디오존데) 지점의 관측자료를 이용하여 표준등압면의 기상요소를 검증하는 것을 말합니다. 관측지점에서 가장 가까운 모델 격자점을 이용하여 검증합니다.|수치예보모델에서 현재의 대기상태에 가장 가깝게 모의하여 생성한 분석장과 예측장을 비교하는 것을 말합니다. 모델 격자에 있는 분석장과 예측장을 일정한 크기 (WMO 기준: 1.5°×1.5°)의 검증격자로 변환하여 검증하며, | ||
| + | |{{WMO 지정 표준관측검증 지점.png? | ||
| + | |||
| + | ==== 1.2. 모델 해상도 ==== | ||
| + | === 1.2.1. 공간 해상도 === | ||
| + | 수치모델은 한정된 컴퓨터 자원을 이용하여야 하고 현재 관측시스템의 관측 한계 때문에 무제한으로 작게 분해하여 모의할 수 없습니다. | ||
| + | |||
| + | 여기서 공간해상도란 대기를 컴퓨터 계산에 적합하게 나타내는 격자점과 격자점 사이의 거리 즉, 격자점이 대표하는 공간규모(수백m~수백㎞)로 이해할 수 있으며 이를 수평해상도라 합니다. 격자점 사이의 거리가 짧을수록 수치모델이 모의할 수 있는 기상현상의 규모도 작아집니다. | ||
| + | |||
| + | 일반적으로 모델의 해상도는 사용가능한 컴퓨터의 성능, 모델이 모의할 영역의 크기, 모델이 모의하고자 하는 가장 작은 기상현상의 규모 등에 의해 결정됩니다. 즉, 컴퓨터의 성능이 우수할수록, | ||
| + | |||
| + | 모델대기는 역직방향 수십 개 층으로 나누어지는데 각 층은 지구표면에 대해 고정된 개수의 격자점을 포함합니다. 모델대기의 최상단 고도와 함께 연직 층수는 모델 대기의 연직 해상도를 결정합니다. 각 격자점에는 각 격자점이 포함하는 대기요소들의 평균 상태를 나타내는 일련의 값들을 갖습니다(아래 그림 1). | ||
| + | {{격자점들과_격자상자.png? | ||
| + | |||
| + | |||
| + | === 1.2.2. 시간 분해능 === | ||
| + | 수치모델에서의 적분은 일정한 시간간격으로 연속적으로 진행되어야 하며 이 시간간격은 다시 컴퓨터의 성능에 의해 좌우됩니다. 시간간격(적분시간)이 짧을수록 보다 많은 수의 계산이 수행됩니다. 미래의 새로운 대기상태를 결정하기 위해서 각 공기덩이와 관계된 전체 방정식 계들이 이 적분시간 간격으로 동시에 계산되어야 합니다. 이로부터 새로운 힘의 장이 계산되고 다음 적분에서 공기덩이들이 어떻게 이동할지를 계산합니다. | ||
| + | |||
| + | 시간분해능은 주어진 적분시간내에 공기덩이가 모델 격자 거리보다 먼 거리를 이동하지 않도록 공간분해능과 조화를 이루어야 합니다. 만약 v가 가장 빠른 속도이고 d(㎞)가 격자거리라 하면 적분시간은 d/v보다 길어서는 안됩니다. 적분이 진행되는 과정에서 각 공기덩이의 이동을 따라 대기상태를 예측하는 것이 아니라 매 적분시간마다 각 격자내 공기의 새로운 상태(기압, | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== 1.3. 한국형수치예보모델 설명 ==== | ||
| + | |||
| + | |||
| + | |||
| + | 한국형수치예보모델은 2011년부터 개발을 시작하여 2020년 4월부터 날씨정보 생산에 활용하였습니다. | ||
| + | |||
| + | 한국형수치예보모델은 육면체구 격자 기반의 전지구모델로 분광요소법 기반 수치계의 비정역학 코어와 | ||
| 고해상도 모델에 적합한 물리과정으로 구성되어 있습니다. 육면체구 격자는 위경도 격자의 극 | 고해상도 모델에 적합한 물리과정으로 구성되어 있습니다. 육면체구 격자는 위경도 격자의 극 | ||
| 특이점 문제를 해결하고 격자 거리가 비교적 균일하도록 고안된 구면 격자입니다(Sadourny, | 특이점 문제를 해결하고 격자 거리가 비교적 균일하도록 고안된 구면 격자입니다(Sadourny, | ||
| 줄 13: | 줄 95: | ||
| 는 3개의 점으로 있으며, 이는 공간해상도 약 12 km입니다. | 는 3개의 점으로 있으며, 이는 공간해상도 약 12 km입니다. | ||
| == 한국형 수지예보모델(KIM)의 격자체계를 설명하기 위한 모식도== | == 한국형 수지예보모델(KIM)의 격자체계를 설명하기 위한 모식도== | ||
| - | {{kim_격자체계모식도.png? | + | {{kim_격자체계모식도.png? |
| (a) ne=10, np=4 인 육면체구 격자, | (a) ne=10, np=4 인 육면체구 격자, | ||
| 줄 19: | 줄 101: | ||
| - | ===== 1.2. 주요특성 | + | |
| - | ^모델명^GDAPS(KIM NE360 NP3)^ | + | ===== 2. 현업 수치예보모델 ===== |
| + | ==== 2.1. KIM-전구(KIM-Global) | ||
| + | === 2.1.1. 기본정보 | ||
| + | ^모델명^KIM-전구(KIM-Global)^ | ||
| |기본모델| KIM(Korea Integrated Model) / KIM-GMODEL-v3.7| | |기본모델| KIM(Korea Integrated Model) / KIM-GMODEL-v3.7| | ||
| |영역|전지구| | |영역|전지구| | ||
| 줄 37: | 줄 122: | ||
| |지표상태|KIM surface analysis(soil moisture, snow) + Climatology| | |지표상태|KIM surface analysis(soil moisture, snow) + Climatology| | ||
| - | + | === 2.1.2. 파일명 === | |
| - | ===== 1.3. 운영현황 ===== | + | kim_g128_ne36_{pres|unis}_h{000~288}.yyyymmddhh.gb2 |
| - | 기상청은 초단기(6시간 이내)~단기예보(4일 이내)~중기(10일 이내)까지 예·특보 지원을 | + | ==== 2.2. KIM-지역모델(KIM-Regional) ==== |
| - | 위해 관심 영역, 기간에 따라 20여 종 수치예보시스템을 운영하고 있습니다. | + | === 2.2.1 기본정보 === |
| - | + | KIM-지역모델은 2022년 5월 12일부터 현업 운영을 시작하였습니다. 동아시아 영역에 대 | |
| - | == 현업 수치예보 시스템 운영현황(2022년 12월 기준) | + | |
| - | {{현업수치예보시스템운영현황.png? | + | |
| - | + | ||
| - | 위 그림은 기상청이 운영하고 있는 주요 수치예보시스템 구성을 요약 한 것으로 2020년 4월부터 현업 운영 중인 한국형수치예보모델(KIM)의 안정적 성능 확보까지 기존 통합모델 | + | |
| - | 기반의 수치예보시스템과 병행 운영 중입니다. 또한, 전지구예보모델인 한국형수치예보모델의 | + | |
| - | 현업 운영에 따른 연계모델(앙상블, | + | |
| - | + | ||
| - | == [표] 기상청 수치예보 시스템 운영 현황(2022년 12월 31일 기준) | + | |
| - | ^시스템(모델)^^수평분해능(연직총수)^운영횟수/ | + | |
| - | |전지구(GDAPS)|전지구예보시스템(KIM NE360 NP3)|12km(91층)|4회|12일(00, | + | |
| - | |::: | + | |
| - | |지역(RDAPS)|지역예보시스템(KIM 3kmL40)|3km(40층)|4회|72시간|대상: | + | |
| - | |국지(LDAPS)|국지예보시스템(UM 1.5km L70)|1.5km(70층)|4회|48시간|대상: | + | |
| - | |초단기(KLAPS)|초단기 배경예측(UM-KLBG)|5km(40층)|4회|36시간|대상: | + | |
| - | |::: | + | |
| - | |::: | + | |
| - | + | ||
| - | + | ||
| - | ===== 1.4. 한국형 지역예보시스템(RDAPS-KIM) ===== | + | |
| - | 한국형 | + | |
| - | System-KIM)는 | + | |
| 해 일 4회 3일(72시간) 예측을 수행하며, | 해 일 4회 3일(72시간) 예측을 수행하며, | ||
| 입니다. | 입니다. | ||
| - | == 한국형 | + | == KIM-지역모델(KIM-Regional) 예측 영역== |
| {{rdaps-kim.png? | {{rdaps-kim.png? | ||
| - | == [표] 한국형 | + | == [표] KIM-지역모델(KIM-Regional)주요 특성 |
| - | ^모델명^RDAPS-KIM(KIM | + | ^모델명^KIM-지역모델(KIM-Regional)^ |
| |수평해상도와 격자 개수|3 km x 3 km / 1, | |수평해상도와 격자 개수|3 km x 3 km / 1, | ||
| |연직층수/ | |연직층수/ | ||
| 줄 83: | 줄 147: | ||
| |지표면|Thermal Diffusion Scheme| | |지표면|Thermal Diffusion Scheme| | ||
| + | === 2.2.2 파일명 === | ||
| + | r030_v040_ne36_{pres|unis|etas}_h{000~072}.yyyymmddhh.gb2 | ||
| + | |||
| + | ==== 2.3. 한국형 수치모델 grib파일별 격자 및 변수 참고 정보 ==== | ||
| + | ^ 구분 ^ 종류 ^ 파일명 ^ 격자 및 변수 정보 ^ | ||
| + | |KIM 전구 | 등압면 | kim_g128_ne36_pres_h??? | ||
| + | |KIM 전구 | 단일면 | kim_g128_ne36_unis_h??? | ||
| + | |KIM 지역(12km) | 등압면 | kim_g120_ne36_pres_h??? | ||
| + | |KIM 지역(12km) | 단일면 | kim_g120_ne36_unis_h??? | ||
| + | |KIM 지역(3km) | 등압면 | r030_v040_ne36_pres_h??? | ||
| + | |KIM 지역(3km) | 단일면 | r030_v040_ne36_unis_h??? | ||
| + | |||
| + | ===== 3. 검색 및 획득 ===== | ||
| + | |||
| + | ==== 3.1. 검색·획득 – 기상청 API허브 ==== | ||
| + | |||
| + | === 3.1.1. 자료 접근 === | ||
| + | * 사이트 : 기상청 API허브 (apihub.kma.go.kr) | ||
| + | * 메뉴 : 수치모델 -> 수치예보모델 -> 한국형수치예보모델(KIM) 자료 조회 | ||
| + | |||
| + | === 3.1.2. 자료 획득 === | ||
| + | * 절차: 회원가입 및 로그인 -> API 메뉴 이동 -> API 활용신청 -> API호출 | ||
| + | * 호출 방법: {{기상관측: | ||
| + | |||
| + | ===== 4. 활용방안 ===== | ||
| + | |||
| + | 소스코드: | ||
| + | |||
| + | === 4.1. 라이브러리 설치 === | ||
| + | |||
| + | <code py> | ||
| + | # API 요청을 위한 requests 라이브러리와 | ||
| + | # 지도 표출을 위한 cartopy 라이브러리, | ||
| + | # 연직단면도 표출을 위한 metpy 라이브러리를 설치합니다. | ||
| + | %pip install requests cartopy metpy | ||
| + | </ | ||
| + | |||
| + | === 4.2. KIM 모델 자료 다운로드 === | ||
| + | |||
| + | 기상청 API허브에 회원가입 후 자신의 인증키를 사용하여 API 요청을 할 수 있습니다. | ||
| + | |||
| + | API 인증키를 코드상에 직접 남겨 사용하는 방식은 다른 사람에게 코드를 공유할때 인증키가 노출되는 문제가 생길 수 있습니다. | ||
| + | |||
| + | 따라서 인증키를 환경변수로 등록하여 코드상에 노출되지 않도록 사용하는 것이 바람직합니다. | ||
| + | |||
| + | <code py> | ||
| + | import os # 환경변수를 불러오는 표준 라이브러리 | ||
| + | |||
| + | # 바람직하지 않은 방법 | ||
| + | # my_api_key = ' | ||
| + | |||
| + | # 인증키를 ' | ||
| + | my_api_key = os.environ[' | ||
| + | </ | ||
| + | |||
| + | <code py> | ||
| + | import requests | ||
| + | import numpy as np # 배열을 다루는 라이브러리 | ||
| + | |||
| + | # KIM 자료를 txt파일로 조회하는 API url | ||
| + | api_url = ' | ||
| + | |||
| + | # 요청인자로 모델 구분, 모델 기반 종류, 자료 종류, 변수명, 고도, | ||
| + | # 사용영역 및 격자영역, | ||
| + | |||
| + | # 1. 모델 구분으로 KIMG를 입력합니다. | ||
| + | group = ' | ||
| + | |||
| + | # 2. 모델 기반 종류로 NE36을 입력합니다. | ||
| + | nwp = ' | ||
| + | |||
| + | # 3. 자료 종류로 등압면(P), | ||
| + | # 여기선 등압면을 사용합니다. | ||
| + | data = ' | ||
| + | |||
| + | # 4. 변수명을 입력합니다. | ||
| + | # 여기선 사용할 변수명으로 기온(Air Temperature, | ||
| + | name = ' | ||
| + | |||
| + | # 5. 고도를 입력합니다. | ||
| + | # 여기선 등압면 24개 레벨을 모두 사용합니다. | ||
| + | pres_levels = np.array([ | ||
| + | 1000, 975, 950, 925, 900, 875, 850, 800, 750, 700, 650, 600, 550, | ||
| + | 500, 450, 400, 350, 300, 250, 200, 150, 100, 70, 50 | ||
| + | ]) | ||
| + | |||
| + | # 6. 사용영역을 전체(F), 일부(S), LCC변환 일부(R)중 하나를 입력합니다. | ||
| + | # 여기선 동아시아 일부 영역을 사용하므로 S를 입력합니다. | ||
| + | # 동아시아 영역의 좌표를 입력하기 위해 전체 영역이 사용하는 좌표계를 이해해야 합니다. | ||
| + | # 전체 영역은 위도[-89.9375, | ||
| + | # 경도[0, 360)를 2880개로 나눈 격자 좌표(0.125간격)를 사용합니다. | ||
| + | # 동아시아 영역이 나타내는 범위를 위도 25.8125 ~ 50.3125, 경도 104 ~ 148로 가정합니다. | ||
| + | # 마지막으로 격자영역은 xmin, ymin, xmax, ymax 형태로 입력합니다. | ||
| + | map = ' | ||
| + | degree_interval = 0.125 | ||
| + | lat_1, lon_1, lat_2, lon_2 = 25.8125, 104, 50.3125, 148 | ||
| + | |||
| + | # 격자 좌표를 계산하기위해 전체영역의 시작 위도를 더해줍니다. | ||
| + | # 그리고 첫 시작점을 1부터 시작시키며 정수로 변환합니다. | ||
| + | sub = ( | ||
| + | np.array([lon_1, | ||
| + | ).astype(int) | ||
| + | |||
| + | # 7. 분석시간을 년월일시(UTC)로 입력합니다. | ||
| + | # 예시로 2023년 8월 9일 06시(UTC)를 입력합니다. | ||
| + | tmfc_utc = ' | ||
| + | |||
| + | # 8. 예측시각을 입력합니다. | ||
| + | # 예시로 24시간 후의 예측을 입력합니다. | ||
| + | hf = 24 | ||
| + | |||
| + | # 9. 마지막으로 제공형태를 ASCI(A), Binary(B) 중 하나를 입력합니다. | ||
| + | # 활용 편의를 위해 이진형태의 파일을 선택합니다. | ||
| + | disp = ' | ||
| + | |||
| + | # 파일 명명 규칙에 따라 24개 레벨의 파일 이름을 저장할 배열을 정의합니다. | ||
| + | # API 응답을 저장할 파일 형식은 bin 파일로 저장합니다. | ||
| + | file_name_list = np.array([ | ||
| + | f" | ||
| + | for level in pres_levels | ||
| + | ]) | ||
| + | |||
| + | # 파일 목록을 출력합니다. | ||
| + | file_name_list | ||
| + | </ | ||
| + | | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | <code py> | ||
| + | # 각 파일의 존재 여부를 확인합니다. | ||
| + | file_exists_list = np.vectorize(os.path.exists)(file_name_list) | ||
| + | |||
| + | # 저장된 파일이 없는 경우에만 API를 요청해 파일을 다운로드합니다. | ||
| + | if not file_exists_list.all(): | ||
| + | # API 요청인자들을 묶어 dictionary로 정의합니다. | ||
| + | api_parameters = { | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | } | ||
| + | # 파일 다운로드를 위한 세션을 만듭니다. | ||
| + | with requests.Session() as session: | ||
| + | # 존재하지 않는 파일에 대해서 반복합니다. | ||
| + | for idx in np.where(~file_exists_list)[0]: | ||
| + | # API 요청인자에 레벨을 입력합니다. | ||
| + | api_parameters[' | ||
| + | |||
| + | # API 요청인자와 함께 API 요청 | ||
| + | response = session.get(api_url, | ||
| + | |||
| + | # 잘못된 응답을 받거나 짧은 에러메세지를 응답으로 받은 경우 에러 메세지 출력 | ||
| + | if response.status_code != 200 or len(response.content) < 300: | ||
| + | raise requests.RequestException( | ||
| + | response.content.decode(' | ||
| + | ) | ||
| + | else: | ||
| + | # 그 외의 올바른 응답에 대해서만 파일로 저장합니다. | ||
| + | with open(file_name_list[idx], | ||
| + | f.write(response.content) | ||
| + | print(f' | ||
| + | </ | ||
| + | kimg_ne36_pres_T_p000_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p975_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p950_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p925_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p900_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p875_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p850_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p800_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p750_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p700_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p650_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p600_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p550_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p500_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p450_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p400_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p350_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p300_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p250_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p200_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p150_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p100_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p070_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | kimg_ne36_pres_T_p050_h024.2023080906.bin 파일 다운로드 완료 | ||
| + | |||
| + | === 4.3. 연직단면도 표출 === | ||
| + | |||
| + | 다운로드받은 24개 레벨의 파일을 읽어 하나의 xarray 데이터셋으로 합쳐서 다룹니다. | ||
| + | |||
| + | <code py> | ||
| + | import xarray as xr # 자료를 다루기 위한 라이브러리 | ||
| + | |||
| + | # 24개 레벨의 파일을 읽어 xarray 데이터셋을 만듭니다. | ||
| + | # xarray 데이터셋은 크게 variables, coordinates, | ||
| + | # attributes는 데이터에 사용된 각종 정보들을 나타냅니다. | ||
| + | xr_array = xr.Dataset( | ||
| + | # variable은 실제 데이터를 담고 있는 변수로 변수이름과 (차원, 데이터)를 dictionary 형태로 입력합니다. | ||
| + | # 데이터는 파일로부터 읽어들이며 이진 파일의 앞의 4byte, 4byte는 데이터의 가로, 세로 격자수를 나타내며 | ||
| + | # 나머지 데이터는 4byte 소수형으로 읽어들입니다. | ||
| + | data_vars={ | ||
| + | ' | ||
| + | [' | ||
| + | np.fromfile(f, | ||
| + | sub[3] - sub[1] + 1, sub[2] - sub[0] + 1 | ||
| + | ) | ||
| + | for f in file_name_list])) | ||
| + | ) | ||
| + | }, | ||
| + | # coordinates는 variable의 차원을 나타내는 변수입니다. | ||
| + | # 앞서 variable의 차원부분에 입력한 이름에 맞게 실제 차원 수를 dictionary 형태로 입력합니다. | ||
| + | coords={ | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | }, | ||
| + | # attributes는 데이터에 사용된 각종 정보들을 나타냅니다. | ||
| + | # API 요청시 사용한 인자들을 dictionary 형태로 입력합니다. | ||
| + | attrs={ | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | } | ||
| + | ) | ||
| + | |||
| + | # 생성한 xarray 데이터셋을 출력합니다. | ||
| + | xr_array | ||
| + | </ | ||
| + | < | ||
| + | Dimensions: | ||
| + | Coordinates: | ||
| + | * isobaric | ||
| + | * lat (lat) float64 2kB 25.81 25.94 26.06 26.19 ... 50.06 50.19 50.31 | ||
| + | * lon (lon) float64 3kB 104.0 104.1 104.2 104.4 ... 147.8 147.9 148.0 | ||
| + | Data variables: | ||
| + | temperature | ||
| + | Attributes: | ||
| + | group: | ||
| + | nwp: NE36 | ||
| + | data: P | ||
| + | name: T | ||
| + | map: S | ||
| + | sub: 833, | ||
| + | tmfc: | ||
| + | hf: 24 | ||
| + | |||
| + | 연직단면도를 표출하기 앞서, 기압 레벨에 따른 한반도 지역의 기온 분포도를 표출합니다. | ||
| + | |||
| + | <code py> | ||
| + | import matplotlib.pyplot as plt # 이미지 표출에 사용되는 라이브러리 | ||
| + | import cartopy.crs as ccrs # 지도 표출에 사용되는 라이브러리 | ||
| + | import cartopy.feature as cfeature | ||
| + | from cartopy.crs import PlateCarree # 지도 표출에 사용되는 라이브러리 | ||
| + | |||
| + | # 분포도에서 색상표 위치, 크기를 조절하는 함수 | ||
| + | from mpl_toolkits.axes_grid1 import make_axes_locatable | ||
| + | |||
| + | # 비교할 분포도는 1000hPa과 200hPa입니다. | ||
| + | # 분포도 내의 최대, 최소 값을 이용해 값의 범위를 구합니다. | ||
| + | isobaric_1 = 1000 | ||
| + | isobaric_2 = 200 | ||
| + | isobaric_1_arr = xr_array[' | ||
| + | isobaric_2_arr = xr_array[' | ||
| + | vmin1, vmax1 = isobaric_1_arr.min() - isobaric_1_arr.min() % 5, isobaric_1_arr.max() - isobaric_1_arr.max() % 5 + 5 | ||
| + | vmin2, vmax2 = isobaric_2_arr.min() - isobaric_2_arr.min() % 5, isobaric_2_arr.max() - isobaric_2_arr.max() % 5 + 5 | ||
| + | |||
| + | # 이미지를 그릴 크기를 지정합니다. | ||
| + | kw = {' | ||
| + | fig, axes = plt.subplots(1, | ||
| + | fig.tight_layout(pad=3) | ||
| + | |||
| + | # 이미지의 제목을 지정합니다. | ||
| + | fig.suptitle(f" | ||
| + | axes[0].set_title(f" | ||
| + | axes[1].set_title(f" | ||
| + | |||
| + | # 이미지를 각 영역에 그립니다. | ||
| + | im1 = axes[0].imshow(isobaric_1_arr, | ||
| + | im2 = axes[1].imshow(isobaric_2_arr, | ||
| + | |||
| + | # 이미지에 해안선과 경계를 표시합니다. | ||
| + | axes[0].coastlines() | ||
| + | axes[1].coastlines() | ||
| + | axes[0].add_feature(cfeature.STATES.with_scale(' | ||
| + | axes[1].add_feature(cfeature.STATES.with_scale(' | ||
| + | |||
| + | # 색상표의 크기와 위치를 조절합니다. | ||
| + | divider1 = make_axes_locatable(axes[0]) | ||
| + | cax1 = divider1.append_axes(' | ||
| + | divider2 = make_axes_locatable(axes[1]) | ||
| + | cax2 = divider2.append_axes(' | ||
| + | |||
| + | # 색상표에 표시될 글자 크기, 제목, 범위를 설정합니다. | ||
| + | cbar1 = fig.colorbar(im1, | ||
| + | cbar2 = fig.colorbar(im2, | ||
| + | cbar1.ax.tick_params(labelsize=8) | ||
| + | cbar1.ax.set_yticks(np.linspace(vmin1, | ||
| + | cbar1.ax.set_title(' | ||
| + | cbar2.ax.tick_params(labelsize=8) | ||
| + | cbar2.ax.set_yticks(np.linspace(vmin2, | ||
| + | cbar2.ax.set_title(' | ||
| + | |||
| + | # 그린 이미지를 표출합니다. | ||
| + | plt.show() | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | 마지막으로 연직단면도를 표출합니다. | ||
| + | |||
| + | <code py> | ||
| + | from metpy.interpolate import cross_section # 연직단면도 계산을 위한 함수 | ||
| + | from pyproj import CRS # 좌표계 형식을 사용하기 위한 라이브러리 | ||
| + | |||
| + | |||
| + | # 연직단면도를 위한 두 점의 좌표를 위·경도 좌표로 입력합니다. | ||
| + | start = (36.9, 120.7) | ||
| + | end = (37.5, 133.4) | ||
| + | |||
| + | # metpy를 활용하기 위해 데이터가 좌표계(CRS)를 인식할 수 있도록 CRS를 등록(assign_crs)합니다. | ||
| + | xr_array = xr_array.metpy.assign_crs(CRS(' | ||
| + | |||
| + | # 데이터를 두 점을 연결하는 선으로 자른 연직단면도로 변환합니다. | ||
| + | cross = cross_section(xr_array, | ||
| + | |||
| + | # 변환된 연직단면도 데이터를 표출합니다. | ||
| + | # 기온 변수의 차원이 lat, lon좌표에서 index(100개)로 변환된 것을 확인할 수 있습니다. | ||
| + | cross | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | Dimensions: | ||
| + | Coordinates: | ||
| + | * isobaric | ||
| + | metpy_crs | ||
| + | lon (index) float64 800B 120.7 120.8 121.0 ... 133.1 133.3 133.4 | ||
| + | lat (index) float64 800B 36.9 36.91 36.93 36.94 ... 37.5 37.5 37.5 | ||
| + | * index (index) int64 800B 0 1 2 3 4 5 6 7 ... 92 93 94 95 96 97 98 99 | ||
| + | Data variables: | ||
| + | temperature | ||
| + | Attributes: | ||
| + | group: | ||
| + | nwp: NE36 | ||
| + | data: P | ||
| + | name: T | ||
| + | map: S | ||
| + | sub: 833, | ||
| + | tmfc: | ||
| + | hf: 24 | ||
| + | |||
| + | <code py> | ||
| + | # 연직단면도를 그릴 크기를 지정합니다. | ||
| + | fig, ax = plt.subplots(figsize=(16, | ||
| + | |||
| + | # 기온을 표출하기 위해 등치선을 채우는 방식(filled contour, contourf)을 사용합니다. | ||
| + | # 레벨은 최소값과 최대값을 이용해 구합니다. | ||
| + | temperature_contour = ax.contourf( | ||
| + | cross[' | ||
| + | levels=np.arange( | ||
| + | cross[' | ||
| + | cross[' | ||
| + | ) | ||
| + | ) | ||
| + | # 등치선의 색상표를 표출합니다. | ||
| + | temperature_colorbar = fig.colorbar(temperature_contour, | ||
| + | temperature_colorbar.ax.set_title(' | ||
| + | |||
| + | # Y축을 로그 스케일(log scale)로 변환합니다. 또, 표출할 범위를 지정합니다. | ||
| + | ax.set_yscale(' | ||
| + | ax.set_ylim(cross[' | ||
| + | ax.set_yticks(np.arange(1000, | ||
| + | ax.set_yticklabels(np.arange(1000, | ||
| + | |||
| + | # 데이터의 좌표계를 정의하고, | ||
| + | data_crs = cross[' | ||
| + | ax_inset = fig.add_axes([0.85, | ||
| + | |||
| + | # start, end 두 점의 위·경도 좌표를 지도가 사용하는 좌표계로 변환하여 지도에 표출합니다. | ||
| + | # 또, 앞서 그린 분포도를 표출합니다. | ||
| + | endpoints = data_crs.transform_points( | ||
| + | ccrs.Geodetic(), | ||
| + | ) | ||
| + | ax_inset.imshow(isobaric_2_arr, | ||
| + | ax_inset.scatter(endpoints[:, | ||
| + | ax_inset.plot(cross[' | ||
| + | |||
| + | # 지도에 해안선 및 경계를 표출합니다. | ||
| + | ax_inset.coastlines() | ||
| + | ax_inset.add_feature(cfeature.STATES.with_scale(' | ||
| + | # 단면도의 제목과 축의 라벨을 지정합니다. | ||
| + | ax_inset.set_title('' | ||
| + | ax.set_title(f' | ||
| + | ax.set_ylabel(' | ||
| + | ax.set_xlabel(' | ||
| + | temperature_colorbar.set_label(' | ||
| + | # 단면도를 표출합니다. | ||
| + | plt.show() | ||
| + | </ | ||
| + | {{: | ||