很多出國深造的同學,都對國外高校中的計算機教學、使用記憶猶新。國内一般院校的老師很多都是從微軟的DOS起步開始搗鼓微型計算機的,基本上對unix系統用的不多。對指令行操作,也停留在dos指令的概念上。最近,一位同學畢業設計遇到了讀取天氣預報資料并顯示在地圖上的問題,來請教我,我們一起在linux下摸索了很久,終于搞定了。在學習過程中,參照了幾篇前人的文章,幫助很大。
基于GFS資料開發行業氣象資訊API(I)
基于GFS資料開發行業氣象資訊API(II)
C++中調用cmd指令行運作腳本處理GDAS資料.
感謝這些朋友的分享!
1 問題背景
該學生畢業設計是做一個天氣圖層,希望GIS顯示出各個區域的溫度高低。搜尋了很多現有的接口,都不滿意,最終在CSDN上“基于GFS資料開發行業氣象資訊API(I)”,找到了一個免費的高大上資料源,在這個網站,每6個小時會更新一次全球的天氣預報,而且是免費的。
GFS應該是全球預報系統的縮寫,“GDAS”也是一種天氣資料縮寫。但這兩個東西,距離GIS圖層可視化還差了很遠很遠,實質上,網站釋出的是每6小時釋出一次的資料檔案。這個資料檔案存儲了很多專題的資料,高度壓縮到一個檔案裡面去。
學生要求我幫助處理的檔案名類似gdas.t00z.pgrb2.0p25.f001,“t00”大概表示格林威治時刻0時釋出的檔案。0p25指的是精度,每0.25度(經緯度)一個點。f001表示的是預測第一個小時的天氣。當然,不同精度、不同釋出時刻和預測時刻,對應的檔案名不同。
該同學的任務是幫助畢業設計小組,提取出一個區域的溫度資料,并入庫。
2 使用wgrib2讀取資料
根據網站的說明,知道需要用一個叫做“wgrib2”的工具進行操作。也是根據官網的指南,發現這個工具可以直接從linux中建構,也可以在windows下安裝OpenGrADS,裡面直接附帶了wgrib2.
2.1 檢視資料成分
我們嘗試下載下傳一個檔案,運作指令行:
[email protected]$wgrib2 gdas.t00z.pgrb2.p25.f000
可以看到資料的所有專題條目,每一行對應了一種資料:
::d=:UGRD:planetary boundary layer:anl:
::d=:VGRD:planetary boundary layer:anl:
::d=:VRATE:planetary boundary layer:anl:
::d=:GUST:surface:anl:
::d=:HGT: mb:anl:
::d=:TMP: mb:anl:
::d=:RH: mb:anl:
::d=:UGRD: mb:anl:
::d=:VGRD: mb:anl:
::d=:O3MR: mb:anl:
::d=:HGT: mb:anl:
::d=:TMP: mb:anl:
……
::d=:PWAT:entire atmosphere (considered as a single layer):anl:
::d=:CWAT:entire atmosphere (considered as a single layer):anl:
::d=:RH:entire atmosphere (considered as a single layer):anl:
::d=:TOZNE:entire atmosphere (considered as a single layer):anl:
::d=:HLCY:- m above ground:anl:
::d=:USTM:- m above ground:anl:
::d=:VSTM:- m above ground:anl:
::d=:PRES:tropopause:anl:
::d=:ICAHT:tropopause:anl:
……
::d=:VWSH:PV=-e- (Km^/kg/s) surface:anl:
::d=:PRMSL:mean sea level:anl:
::d=:WAVH: mb:anl:
包羅萬象。可是,這些資料是什麼意思呢?檢視指令行選項,才發現這個wgrib2真的好好多的參數哦!最終發現了-V和-v參數,可以輸出更多的内容。
[email protected]$wgrib2 gdas.t00z.pgrb2.p25.f000 -V
輸出:
::vt=:planetary boundary layer:anl:UGRD U-Component of Wind [m/s]:
ndata=:undef=:mean=.:min=-:max=
grid_template=:winds(N/S):
lat-lon grid:( x ) units e- input WE:NS output WE:SN res
lat to - by .
lon . to by . #points=1038240
::vt=:planetary boundary layer:anl:VGRD V-Component of Wind [m/s]:
ndata=:undef=:mean=.:min=-:max=
grid_template=:winds(N/S):
lat-lon grid:( x ) units e- input WE:NS output WE:SN res
lat to - by .
lon . to by . #points=1038240
……
::vt=: mb:anl:TMP Temperature [K]:
ndata=:undef=:mean=:min=:max=
grid_template=:winds(N/S):
lat-lon grid:( x ) units e- input WE:NS output WE:SN res
lat to - by .
lon . to by . #points=1038240
……
::vt=:mean sea level:anl:PRMSL Pressure Reduced to MSL [Pa]:
ndata=:undef=:mean=:min=:max=
grid_template=:winds(N/S):
lat-lon grid:( x ) units e- input WE:NS output WE:SN res
lat to - by .
lon . to by . #points=1038240
::vt=: mb:anl:WAVH -Wave Geopotential Height [gpm]:
ndata=:undef=:mean=:min=:max=
grid_template=:winds(N/S):
lat-lon grid:( x ) units e- input WE:NS output WE:SN res
lat to - by .
lon . to by . #points=1038240
::vt=:surface:anl:LANDN Land-sea coverage (nearest neighbor) [land=,sea=] [-]:
ndata=:undef=:mean=.:min=:max=
grid_template=:winds(N/S):
lat-lon grid:( x ) units e- input WE:NS output WE:SN res
lat to - by .
lon . to by . #points=1038240
不但包含了我們需要的溫度參數,還有好多好多東西,比如氣壓、風力、風向。
2.2 嘗試導出實際資料
仔細閱讀了指令行說明,發現這個工具竟然可以直接導出為bin或者csv、text
不妨試試看:
$wgrib2 gdas.t00z.pgrb2.p25.f000 -csv .csv -i
而後,直接輸入某一行資料,回車,即可生成一個csv檔案了。
比如:
$wgrib2 gdas.t00z.pgrb2.p25.f000 -csv .csv -i
::d=:TMP: mb:anl:[回車]
産生了一個csv檔案,用wps直接打開。
産生時刻 | 預報時刻 | 内容 | 氣壓? | 緯度(度) | 經度(度) | 溫度(K) |
---|---|---|---|---|---|---|
…… | ||||||
2018-05-26 00:00:00 | 2018-05-26 00:00:00 | TMP | 400 mb | -0.5 | -69 | 222.6 |
2018-05-26 00:00:00 | 2018-05-26 00:00:00 | TMP | 400 mb | -0.25 | -69 | 222.6 |
2018-05-26 00:00:00 | 2018-05-26 00:00:00 | TMP | 400 mb | -68.75 | 222.6 | |
2018-05-26 00:00:00 | 2018-05-26 00:00:00 | TMP | 400 mb | 0.25 | -68.75 | 222.5 |
…… |
可見,如果有一個資料庫,可以直接錄入。不過,由于存在很多組溫度資料,對應了不同的大氣層壓力,也就是海拔,我們如果每一個參數都需要手工的導出,未免太麻煩了。實際上,官方文檔中,有例子使用管道直接導出。
3 使用 grep 配合管道批量篩選資料
unix 下的很多程式,都是使用管道進行通信的。使用管道進行通信,可以級聯使用,即使用“|”符号前後貫通各個程序。 當使用管道時,“|”符号左側的程序标準輸出(stdout)會和符号右側程序的标準輸入(“stdin”)直接對接。這就相當于是把螢幕輸出直接送給了下一個程序的輸入。
3.1 管道操作
按照官網的例子,我們可以使用:
$wgrib2 gdas.t00z.pgrb2.p25.f000 | grep ':TMP:' |wgrib2 gdas.t00z.pgrb2.p25.f000 -lola :: :: out.csv spread -i
直接擷取東經100~125度(100,100+100×0.25),北緯 20~45度(20,20+100×0.25)的所有溫度資料,存儲為csv格式。篩選得到感興趣的資料,有了結構化的資料,故而直接建立表格即可。表格包括時刻、經度、緯度、氣壓(海拔)、溫度幾個參數。
3.2 詳細解釋
這裡需要解釋的就是linux的管道啦!其實,這個指令行共運作了3個主要程序。
程序1
wgrib2 gdas.t00z.pgrb2.p25.f000
會列出本檔案中包含的所有資訊,正如2.1裡面列出的一模一樣。
程序2
會把程序1的輸出,作為輸入,并篩選出含有溫度标記“TMP:”的行。
我們運作
可以看到
::d=:TMP: mb:anl:
::d=:TMP: mb:anl:
::d=:TMP: mb:anl:
……
::d=:TMP:PV=e- (Km^/kg/s) surface:anl:
::d=:TMP:PV=-e- (Km^/kg/s) surface:anl:
程序3
wgrib2 gdas.t00z.pgrb2.p25.f000 -lola :: :: out.csv spread -i
即執行了多次2.2節的操作,實質上,程序2的輸出作為程序3的輸入,等于手工敲了好多行。
此外,一些額外的參數用來規定格式、區域:
-lola 參數
規定區域,後面跟着四部分:
經度範圍 | 緯度範圍 | 檔案名 | 格式 |
---|---|---|---|
開始經度:采集個數:采集間隔 | 開始緯度:采集個數:采集間隔 | 輸出檔案 | 檔案格式 |
100:100:0.25 | 20:100:0.25 | out.csv | spread |
-i 參數
表示從stdin輸入要導出的内容。
導出結果
可以看到,導出的資料如下:
longitude | latitude | value |
---|---|---|
100.000000 | 20.000000 | 259.5 |
100.250000 | 20.000000 | 259.6 |
…… | ||
124.500000 | 44.750000 | 264.9 |
124.750000 | 44.750000 | 264.9 |
文本檔案每組一萬行,即100×100個采集經緯度位置。共有好多組,分别對應了篩選出的各組資料。我們把這個交給畢業設計小組的組員,就能夠導入PostgreSQL資料庫中啦。
4 使用octave 可視化溫度資料
目前,學生的GIS還沒做好。我建議他使用Qt+fcgi的方式直接生成半透明的圖檔疊加到OpenStreetMap上去。現在,我們先使用octave對溫度進行讀取,可以直接繪制出全球的溫度等值線。
為了友善octave讀取,我們輸出為二進制格式,還是用管道一步到位。
$wgrib2 gdas.t00z.pgrb2.p25.f000 | grep ':TMP:' |wgrib2 gdas.t00z.pgrb2.p25.f000 -lola :: :: out.bin bin -i
這樣會生成一個含有所有溫度資訊的二進制檔案。二進制檔案的格式是
位元組長度1 ,内容, 位元組長度1,位元組長度2, 内容, 位元組長度2,……
内容直接就是float32類型的矩陣,由于我們導出的是一個區域,實際上有100x100個點。繪制腳本僅僅導出一部分資料進行繪制,否則太多了。
clear
lats = ::;
lons = ::;
[mx,my] = meshgrid(lons,lats);
fid = fopen('out.bin','rb');
asize = fread(fid,[],'uint32');
allv = fread(fid,[,],'float32');
ct = ;
while (asize==)
ct = ct + ;
if (ct>= && ct <=)
subplot(,,ct-);
mesh(mx,my,allv);
endif
asize = fread(fid,[],'uint32');
asize = fread(fid,[],'uint32');
allv = fread(fid,[,],'float32');
endwhile
fclose(fid);
輸出圖像是幾個海拔高度下的溫度分布,機關為開爾文(K):
4 後記
在幫助學生完成了後續的可視化工作後,還是覺得意猶未盡。不知道學習氣象的同學知不知道國内氣象資料的開發情況,特别是有沒有這樣的開放資料網站。學生給我看的國内的天氣預報接口都太花哨、卻不夠深入、友善——做地理資訊的展示,原始資料是最合适的選擇。
4.1關于資料網站
看到這個網站的美工,不由得想起90年代的門戶。雖然很土,但是配合了如此的内容,真的有一種老派JazzBand的感覺。如果稍微深入閱讀一下網站的說明,就會發現這個資料源背後,是一群從80年代就開始,用fortran寫代碼、在unix系統裡做研究的超級神人,以及他們帶出的學生。能夠把如此多的科學參數,整合到一起,有序的管理起來,同時,開發出非常靈活、有效的工具鍊進行釋出,本身就非常厲害了。更可貴的是,文檔也非常通俗易懂,這種科學精神真的值得我們學習。
4.2留學生的計算機技能準備
出國留學的同學,一定會發現國外大學與國内的不同。有些大學論文要求用latex,周圍同學做筆記,用的也是libreoffice等等開源文本處理器。計算實驗用Matlab學生版是有的,也有VC++ 可用,但學習一下python, Octave,GNU C, Linux絕對沒有壞處——這樣想抄别人的也好抄。