pythonでgrib2フォーマットのファイルを触れる環境を用意する(Docker編)

最近、機械学習のサンプルデータとして、気象庁が公開しているアメダスデータを使用している記事をいくつか見かけるようになりました。
一方、気象庁が公開している面的な予報のデータとして、GSMやMSMという数値予報シミュレーションの結果があるのですが、これらのデータを活用した記事というのは見たことがありません。
本記事では、GSMなどの数値予報データのフォーマットの1つであるgrib2形式をpythonから扱えるようにするpygribについて紹介します。

# 数値予報とgrib2
現代の気象予測の技術において大きな位置を占めるのが、数値予報です。
数値予報とは[気象庁によれば](http://www.jma.go.jp/jma/kishou/know/whitep/1-3-1.html)…
> 数値予報は、物理学の方程式により、風や気温などの時間変化をコンピュータで計算して将来の大気の状態を予測する方法です。

要は地球の状態をコンピューターでシミュレーションして、気象予測をする技術です。
気象予報の現場では、この数値予報のデータに後処理を加えたものを利用したり、複数の数値予報結果からもっともらしいものを選択したりといった形で予報を作成していることが多いと思います。

シミュレーションの手法にはいくつか種類がありますが、シミュレーション結果はGPV(grid point value)という形式で提供されることがほとんどです。
GPVは地球上を一定間隔の格子に区切り、その格子ごとに気温や風速といったデータが格納されます。[^ポストプロセス]
気象予測ではこの格子状のデータが時間方向に対して複数格納されたGPVデータを扱うことが多いです。
このGPVの保存形式の1つがgrib2フォーマットで、気象庁のデータも多くがこの形式で配布されています。

[^ポストプロセス]: 格納された値は格子点の値や平均値ですので、そのままの値を格子点内の任意地点の予報として使うことはあまりせず、上述のように後処理を加えることが多いです。

GPVの実際のデータを見たい場合[GPV 気象予報](http://weather-gpv.info/)などから見ることができます。
実際はグリッドごとのデータですが、可視化の際には適当な内挿処理がされていることも多いです。



# pygribの環境構築 on docker
pythonからgrib2データを扱う場合いくつか選択肢があるようですが、今回はpython3に対応している[pygrib](http://jswhit.github.io/pygrib/docs/)を利用します。[^python3]
普通にやるとECMWF(ヨーロッパ中期予報センター)の公開する[grib_api](https://software.ecmwf.int/wiki/display/GRIB/Home)[^eccodes]のインストールで詰まる可能性があるので、今回はanacondaで入れてしまいます。さらに折角なのでdocker上に構築してしまいます。
これで、環境依存でインストールに失敗する確率はかなり低くなると思います。


[^python3]: 他のモジュールは以前(2016年前半)試した際に2系にしか対応していなかったのですが、現在は対応しているかもしれません。
[^eccodes]: 最近は[ecCodes](https://software.ecmwf.int/wiki/display/ECC/ecCodes+Home)の使用が推奨されているようです。

Dockerfileは以下の通りです。

```bash:Dockerfile
FROM ubuntu:latest
MAINTAINER hangyo

# パッケージのインストールとアップデート
RUN apt-get update && apt-get -y upgrade
RUN apt-get -y install build-essential
RUN apt-get -y install git vim curl wget
RUN apt-get -y install zlib1g-dev \
libssl-dev \
libreadline-dev \
libyaml-dev \
libxml2-dev \
libxslt-dev \
libncurses5-dev \
libncursesw5-dev 

# pyenv のインストール
RUN git clone git://github.com/yyuu/pyenv.git /root/.pyenv
RUN git clone https://github.com/yyuu/pyenv-pip-rehash.git /root/.pyenv/plugins/pyenv-pip-rehash
ENV PYENV_ROOT /root/.pyenv
ENV PATH $PYENV_ROOT/bin:$PATH
RUN echo 'eval "$(pyenv init -)"' >> .bashrc

# anaconda のインストール
ENV ANACONDA_VER 4.1.1
ENV LD_LIBRARY_PATH=/lib/x86_64-linux-gnu:$PYENV_ROOT/versions/anaconda3-$ANACONDA_VER/lib
RUN pyenv install anaconda3-$ANACONDA_VER
RUN pyenv global anaconda3-$ANACONDA_VER
ENV PATH $PYENV_ROOT/versions/anaconda3-$ANACONDA_VER/bin:$PATH

# ライブラリのアップデート
RUN conda update -y conda
RUN pip install --upgrade pip
RUN conda install -c conda-forge pygrib=2.0.2
RUN conda install -c conda-forge jpeg


RUN mkdir /temp
```

anacondaのバージョンは適宜修正してください。
anacondaのインストールまでは下記リポジトリを参考(丸写しとも)にしました。
https://github.com/iriya-ufo/ml-anaconda

# サンプルデータの準備
buildして起動させる前に、grib2のサンプルになるファイルを用意しましょう。
今回は京大の生存研の[気象庁データ公開ページ](http://database.rish.kyoto-u.ac.jp/arch/jmadata/)のデータを利用させてもらいます。

```
wget -P somepath/ http://database.rish.kyoto-u.ac.jp/arch/jmadata/data/gpv/original/2017/01/02/Z__C_RJTD_20170102000000_MSM_GPV_Rjp_Lsurf_FH00-15_grib2.bin
```
これは2017年1月2日0時(UTC)を初期時間とする気象庁MSMの地表面(surface)のFT(forecast time:初期時間からの時間)0hから15hまでの予報データになっています。
普通の人が数値予報結果で遊ぶ場合は、地表面データで十分だと思います。

細かい注意点ですが、somepathにデータが保存されますが、Dockerfileとは別の場所に保存しましょう。
dockerの挙動の問題なのですが、dockerはdocker build時にDockerfileのディレクトリ以下のデータをdocker daemonに転送して、docker daemonがbuildを行います。
このため、Dockerfile以下にgrib2を置くと必要以上に転送に時間がかかってしまうためです。
http://kimh.github.io/blog/jp/docker/gothas-in-writing-dockerfile-jp/ あたりが参考になります。

# 読み込みテスト
まずは、buildとrunしてコンテナの中に入ります。

```bash
cd path_of_Dokcerfile
docker build -t pygrib_ubuntu .
docker run -it -v /somepath:/temp pygrib_ubuntu
```

これで、dockerコンテナの中に入れるはずです。
`ls /temp`をしてみて、`Z__C_RJTD_20170102000000_MSM_GPV_Rjp_Lsurf_FH00-15_grib2.bin`があることを確認できれば、マウントも成功です。

最後に、pygribのテストですが

```python:
import pygrib
grbs = pygrib.open('/temp/Z__C_RJTD_20170102000000_MSM_GPV_Rjp_Lsurf_FH00-15_grib2.bin')
for grb in grbs:
    print(grb)
```
をした結果が

```
1:Pressure reduced to MSL:Pa (instant):regular_ll:meanSea:level 0:fcst time 0 hrs:from 201701020000
2:Surface pressure:Pa (instant):regular_ll:surface:level 0:fcst time 0 hrs:from 201701020000
3:10 metre U wind component:m s**-1 (instant):regular_ll:heightAboveGround:level 10 m:fcst time 0 hrs:from 201701020000
4:10 metre V wind component:m s**-1 (instant):regular_ll:heightAboveGround:level 10 m:fcst time 0 hrs:from 201701020000
...
172:Medium cloud cover:% (instant):regular_ll:surface:level 0:fcst time 15 hrs:from 201701020000
173:High cloud cover:% (instant):regular_ll:surface:level 0:fcst time 15 hrs:from 201701020000
174:Total cloud cover:% (instant):regular_ll:surface:level 0:fcst time 15 hrs:from 201701020000
175:Total precipitation:kg m-2 (accum):regular_ll:surface:level 0:fcst time 14-15 hrs (accum):from 201701020000
```
のようになればOKです。

pygribの具体的な使い方については、また別の記事にしたいと思います。