LoginSignup
2
6

More than 3 years have passed since last update.

PyBufrKitを使って流域雨量指数BUFRをデコードする

Posted at

はじめに

気象庁の洪水警報の危険度分布の基となる流域雨量指数というデータがある。このデータは河川の流量に相当する量を表し、3次メッシュコードと河川コードごとに値が定義されており、BUFR4形式で格納されている。BUFRをデコードする方法は様々だが、流域雨量指数では気象庁独自のローカルテーブルが用いられているため、どのツールでもローカルテーブルを指定しないと読み出すことができない。

「流域雨量指数 BUFR」で検索すると、BUFR4フォーマットの解読方法という、カナダのBUFRライブラリlibECBUFRを用いた方法がヒットする。もちろんこれでもよいのだが、インストールがややめんどくさいこと、最近流行りのPythonを使うと何かと便利なので、PyBufrKitと呼ばれるPythonパッケージの使い方を調査した。

使い方

インストール

condaではインストール出来ないようなので、pip install pybufrkitを叩く。

ローカルテーブルの指定

流域雨量指数BUFR用いられるテーブルの確認

まず配信資料に関する技術情報第446号を読んで、流域雨量指数BUFRで用いられるテーブルに関するパラメータを確認する。
bufr_a.png

あるいはpybufrkitコマンドを叩いても、エラーは出るが確認できる。テーブルに関するパラメータは以下の通り。

info
$ pybufrkit info (BUFRファイル)
(略)
master_table_number = 0
originating_centre = 34
originating_subcentre = 0
master_table_version = 26
local_table_version = 1

マスターテーブルのダウンロード

上記のパラメータに対応するPyBufrKit用のJSON形式のマスターテーブルを、PyBufrKitのGitHubからダウンロードする。読み込まれるファイルはtables/{master_table_number}/0_0/{master_table_version}内にあるTableB.jsonTableD.jsonである(同じディレクトリ内にcode_and_flag.jsonもあるが、今回は無くても動いた)。したがって今回の場合、https://github.com/ywangd/pybufrkit/tree/master/pybufrkit/tables/0/0_0/26tables以下をダウンロードすればよい。このダウンロードしたtablesディレクトリの場所は、実行時に指定するため、好きな場所に置くことができる。

ダウンロードしたJSON形式のテーブルの中身を確認してみよう。まずはTableBから。

0/0_0/26/TableB.json
{"000001": ["TABLE A: ENTRY", "CCITT IA5", 0, 0, 24, "Character", 0, 3]}

この意味はWMOのTableBの仕様書を見るとわかりやすい。
TableB.png
うしろ3つはCREX用で使われないため、ローカルテーブルを自作するときはダミーで埋めてよい。

つぎにTableDを見てみる。

0/0_0/26/TableD.json
{
    "300002": ["", ["000002", "000003"]],
    "300003": ["(F, X, Y of descriptor to be added or defined)", ["000010", "000011", "000012"]]
}

これについてもWMOのTableDの仕様書と比較してみると意味が分かる。
TableD.png

JMA用ローカルテーブルの作成

テーブルの書式が分かったところで、JMAのローカルテーブルを以下のディレクトリに作成する。
tables/{master_table_number}/{originating_centre}_{originating_subcentre}/{local_table_version}/Table{B,D}.json
具体的にはtables/0/34_0/1/Table{B,D}.jsonとなる。

まずTableBについて、配信資料に関する技術情報第446号の「要素記述子」という表を見る。
TableB_JMA.png

したがって、以下のファイルを作成すれば良い。

0/34_0/1/TableB.json
{
    "008021": ["TIME SIGNIFICANCE", "CODE TABLE", 0, 0, 5, "CODE TABLE", 0, 2],
    "004001": ["YEAR", "YEAR", 0, 0, 12, "YEAR", 0, 4],
    "004002": ["MONTH", "MONTH", 0, 0, 4, "MONTH", 0, 2],
    "004003": ["DAY", "DAY", 0, 0, 6, "DAY", 0, 2],
    "004004": ["HOUR", "HOUR", 0, 0, 5, "HOUR", 0, 2],
    "004005": ["MINUTE", "MINUTE", 0, 0, 6, "MINUTE", 0, 2],
    "001210": ["RIVER CODE", "Numeric", 0, 80000000, 24, "Numeric", 0, 8],
    "005240": ["INDEX OF LATITUDE FOR 1ST ORDER MESH", "Numeric", 0, 0, 7, "Numeric", 0, 4],
    "006240": ["INDEX OF LONGITUDE FOR 1ST ORDER MESH", "Numeric", 0, 0, 7, "Numeric", 0, 4],
    "005241": ["INDEX OF LATITUDE FOR 2ND ORDER MESH", "Numeric", 0, 0, 4, "Numeric", 0, 2],
    "006241": ["INDEX OF LONGITUDE FOR 2ND ORDER MESH", "Numeric", 0, 0, 4, "Numeric", 0, 2],
    "005242": ["INDEX OF LATITUDE FOR 3RD ORDER MESH", "Numeric", 0, 0, 4, "Numeric", 0, 2],
    "006242": ["INDEX OF LONGITUDE FOR 3RD ORDER MESH", "Numeric", 0, 0, 4, "Numeric", 0, 2],
    "013212": ["RUNOFF INDEX (HIGH ACCURACY)", "Numeric", 1, 0, 12, "Numeric", 0, 4]
}

TableDについても同様に、配信資料に関する技術情報第446号の「集約記述子」という表を見る。
TableD_JMA.png

したがって、以下のファイルを作成すれば良い。

0/34_0/1/TableD.json
{
    "301011": ["", ["004001", "004002", "004003"]],
    "301012": ["", ["004004", "004005"]],
    "301200": ["", ["005240", "006240", "005241", "006241", "005242", "006242"]]
}

コマンドラインでの使い方

help
$ pybufrkit -h
usage: pybufrkit [-h] [-v] [--info | --debug] [-d DEFINITIONS_DIRECTORY]
                 [-t TABLES_ROOT_DIRECTORY]
                 command ...
  • -tで作成したテーブルのディレクトリを指定する
  • ファイル情報のみを表示
    • pybufrkit -t ./tables info ${bufrfile}
  • テキスト形式にデコードする(かなり冗長)
    • pybufrkit -t ./tables decode ${bufrfile}
  • JSON形式にデコードする(値だけが格納される)
    • pybufrkit -t ./tables decode -j ${bufrfile}

Pythonモジュールとしての使い方

JSONに変換するサンプルプログラム

bufr2json.py
import os
from pybufrkit.decoder import Decoder
from pybufrkit.renderer import FlatJsonRenderer


class BufrConverter:
    def __init__(self):
        self.TOPDIR = os.path.dirname(os.path.abspath(__file__))
        self.decoder = Decoder(tables_root_dir=f"{self.TOPDIR}/tables")
        self.renderer = FlatJsonRenderer()

    def convert(self, ini, region):
        filename = f"Z__C_RJTD_{ini}_MET_SEQ_Ggis1km_Proi_Aper10min_RJsuikei{region}_ANAL_bufr4.bin"
        filepath = f"{self.TOPDIR}/bufr/{filename}"
        with open(filepath, 'rb') as buf:
            bufr_message = self.decoder.process(buf.read())
        json = self.renderer.render(bufr_message)
        return json

作業中に出た警告とその意味のメモ

これらの警告を解消しないと、JSONに出力したときなどにエラーメッセージも同時にはき出されて邪魔であった。参考までにメモ。

  • WARNING: Fallback to default master table version 33 (26 not found)
    • BUFRで指定されているマスターテーブルtables/0/0_0/26がなく、最新版のtables/0/0_0/33が存在する場合、そちらにフォールバックされる
  • WARNING: Cannot find sub-centre 0 nor valid default. Local table not in use.
    • BUFRで指定されているローカルテーブルtables/0/34_0/1が見つからない場合、ローカルテーブルは用いられない
2
6
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6