Subject: Re: NetCDF



塩谷です. 

NetCDF について"沖 理子＠東大気候センター"さんから問い合わせがありまし
た. 返事は電脳の方にも CC しても良いとのことでしたので, そのつもりで以
下を書かせていただきます. 

以下の話しは私が現在手元に持っているマニュアル "NetCDF User's Guide:
An Interface for Data Access, Version 2.0, October 1991" にもとづいて
います. さっき, ちょっと ftp サイトをのぞいてみたら V2.3.1 なる tar ファ
イルが置かれていました. マニュアルの章構成等に変更があるのかも知れませ
んが, tar を解凍してマニュアルを再出力するのも気乗りがしなかったので, 
とりあえず手元のマニュアルにしたがって話しを進めさせてもらいます. 

テクニカルな話しは私自身詳しくないので, どちらかというと1ユーザーとし
て実際に使ってみた感想, といったノリの話しになるかと思いますが, 悪しか
らず. 技術的な話しや, 歴史的ないきさつ, 他にもあるこの手のソフトとの比
較等は増田さんあたりの方がお詳しいのではないかと思います(勝手に振って
ごめんなさい). 

1. 概要

いろんな計算機を使って仕事をしていると, 計算機ごとに floating の内部表
現が違っていたりして, データファイルの読み書きに苦労することがあります.
NetCDF はマシンに依存しない形でデータを読み書きするための道具です.
NetCDF のライブラリが正しく移植されていれば, データファイルはたとえば 
ftp で転送するだけで, 異なるマシンでも同じソースコードを使って読み書き
できます.  インターフェイスとしては Fortran と C が用意されています.

また, NetCFD ファイルには, データの他にそのデータの属性(データの種類や
その単位, グリッド情報など)を記述できるので, 必要な情報を正しく記述し
ておけば, そのファイル内で完結して情報を管理できます. つまり, これまで
ですとファイルにはドキュメントがつきものでしたが, ちゃんと情報の記述さ
れた NetCDF ファイルですと, ファイルさえもらってくれば(アクセスできれ
ば), 内部に記述された情報にしたがって読み書きのプログラムを書くことが
できます.

あと, 便利だと思うのは NetCDF では多次元のデータをハンドリングできます
が, 必要な断面を簡単に読み出せる(あるいは書き出せる)点です. データ領域
に対してばかでかい配列を切って, その配列を操作するようにしてデータが取
り扱えるというのは我々のような, 空間・時間の多次元データを扱うものにとっ
て, 見通しの良いプログラミングができ非常にありがたいものです. 

私自身 NCAR で UARS という衛星データの解析をやっていますが, 測器によっ
て, またそれぞれの物理量によって, データのある緯度範囲や高度範囲が異なっ
ていますが, そういった情報も NetCDF ファイルに書き込んでおくことで, ア
クセスするファイル毎にプログラムを書き換えることなく仕事ができてなかな
か便利であると感じています. 

2. 入手方法

anonymous ftp で unidata.ucar.edu (128.117.140.3) から入手できます. 
pub/netcdf.tar.Z がそれです. 1MB 程の大きさがありますので, みんなで太
平洋を横断して取りにいくのも考えものでしょうから, 最新版を電脳サーバー
の方に持ってきておきました. 適切な置き場所が分からないので今は 
~shiotani/tar の下に置いてありますが, すぐに ftp 領域のしかるべき場所
に置かれると思います. 案内をお待ち下さい.

3. ライブラリの構築

手持ちのマニュアルでは, Sun SPARCstation (SunOS), DEC VAX (VMS,Ultrix), 
DECstation (Ultrix), IBM RISC System 6000 (AIX), CRAY YMP (UNICOS),
IBM PS/2 (MSDOS,OS/2) で動作を確認しているとあります. 

以前試しに make してみたのですが, Sun では問題なかったけど, IBM のマシ
ンでは書いてある通りにやっても(README の読解不足かも知れませんが)うま
くいきませんでした.

ここのところが問題で, NetCDF のライブラリが正しく移植できれば, 確かに
ネットワーク透過な心地よい環境といえるのですが, かんじんのライブラリの
移植に困難を伴うようなものだと何にもならない. この辺は徐々に改善されて
いくでしょうが, 以前増田さんが指摘されていたように, ファイルの仕様がユー
ザーレベルだと全く分からないというところが NetCDF の問題点の一つでしょ
う. 

4. NetCDF ファイル

マニュアルの2章の始めにある例を引用します. これは CDL (network Common
Data form Language) で書かれた例です. これを ncgen というコマンドに通
すと対応する NetCDF ファイルができます. またその NetCDF ファイルを 
ncdump というコマンドでダンプすると CDL にしたがったほぼ下記の例と等価
なアスキーファイルが生成されます. 

netcdf example_1 {  // example of CDL notation for a netCDF file

dimensions:          // dimension names and sizes are declared first
        lat = 5, lon = 10, level = 4, time = unlimited;

variables:           // variable types, names, shapes, attributes
        float   temp(time,level,lat,lon);
                temp:long_name     = "temperature";
                temp:units         = "celsius";
        float   rh(time,lat,lon);
                rh:long_name = "relative humidity";
                rh:valid_range = 0.0, 1.0;      // min and max
        int     lat(lat), lon(lon), level(level);
                lat:units       = "degrees_north";      
                lon:units       = "degrees_east";
                level:units     = "millibars";
        short   time(time);
                time:units      = "hours";
        // global attributes
                :source = "National Weather Service";
                :base_time = "1990 11 25 12:00";

data:                // optional data assignments
        level   = 1000, 850, 700, 500;
        lat     = 20, 30, 40, 50, 60;
        lon     = -160,-140,-118,-96,-84,-52,-45,-35,-25,-15;
        time    = 12;
        rh      =.5,.2,.4,.2,.3,.2,.4,.5,.6,.7,
                 .1,.3,.1,.1,.1,.1,.5,.7,.8,.8,
                 .1,.2,.2,.2,.2,.5,.7,.8,.9,.9,
                 .1,.2,.3,.3,.3,.3,.7,.8,.9,.9,
                  0,.1,.2,.4,.4,.4,.4,.7,.9,.9;
}

この例から分かるように NetCDF ファイルは dimensions, variables,
attributes といった構成要素からなります. dimensions, variables あたりは
見たら分かりますよね. attributes は例えば, temp:unit とか :source など
がそうです. 

小さなデータファイルですと, こうやって CDL で書いておいて ncgen を通し
て NetCDF ファイルを作ることもできます. もちろんこれらの操作をすべて 
Fortran なり C のプログラムを書いておこなうこともできます. ただ, 情報
が多くなるとプログラムを書いて NetCDF ファイルを生成するのは結構めんど
くさいので, わたしはもっぱら dimensions, variables, attributes などを 
CDL で定義してデータが空の NetCDF ファイルをいったん作成し, データ部分
はプログラムを用いて書き出すようにしています. 

5. NetCDF ライブラリ

マニュアルでは4章以下, NetCDF ライブラリに関する解説が延々8章まで続き
ます. 最初はゾッとしますが, Fortran と C のルーチンがダブって説明され
ているので, 実質的にはそれほどの量ではありません. やはりざっと目を通さ
れることを勧めます. 

各ルーチンのコンセプトははっきりしているので, 使い方という点ではそれほ
ど困難を感じませんでした. しかし, 用意されているルーチンが非常に下位の
基本ルーチンだけで, 実際に使う分には正直いって使い易いとはいえないと思
います. 例えていえば, 電脳 SGKS の szpack レベルのルーチンが提供されて
いるだけで, sgpack レベルがないといった感じです. 

たとえば, 上記の例で temp:units の中身が知りたいと思うと, まず ncvid 
というルーチンで temp という variable の variable ID を知った上で, そ
の ID をもとに ncagtc というルーチンで文字型 attribute の units の中身
を尋ねるという手順となります. パフォーマンスを追求するという意味では,
次に temp:long_name が欲しくなった時に以前に求めた variable ID を使え
ばいいので効率は良いのですが, 1ユーザーとしては variable ID などには興
味がなくて, パフォーマンスが少しぐらい悪くてもいいから temp:unit の中
身は何かが知りたいわけです.

というわけで, 私自身は NetCDF のルーチンにかぶせる形で, もう一段上位の
ライブラリを書いて使っています. これらはもちろん NetCDF のオリジナルの
ライブラリと共存可能です. これらのルーチンも tar ファイルをつくって電
脳サーバーに置いてあります. (NetCDF 本体と同じく, 案内をお待ち下さい)
dcl-4.x を使っていますので使う時はそちらもリンクして下さい. なお, ソー
スコードの中では Fortran 非標準の include 文, および小文字によるコーディ
ングを行なっています. (include 文は NetCDF ライブラリを用いる上で必須
となっています)

実際に使おうという人以外は興味がないでしょうが, マニュアルがないので以
下にルーチンの簡単な説明をしておきます. 詳しくはソースと NetCDF のマニュ
アルを見て下さい. またこれらを使ったデモプログラムを ncdtest.tar.Z と
しておいておきます. このパッケージを書いていた時のデモプログラム群でし
て, だいたい使い方が分かると思います. 

  a. ファイルの取り扱い

  nxopen(ncdfid,cfname,cfmode)               : NetCDF ファイルの open
  nxdefm(ncdfid,ldmode)                      : define mode の設定
  nxclos(ncdfid)                             : NetCDF ファイルの close
  nxfilm(ncdfid,lfmode)                      : fill mode の設定

  b. dimensions

  nxddef(ncdfid,cdname,ndsize)               : dimension の定義
  nxdqsz(ncdfid,cdname,ndsize)               : dimension の参照

  c. variables

  nxvdef(ncdfid,cvstrc,cvtype)               : variable の定義
  nxvp1x(ncdfid,cvname,mindex,valuex)        : 1変数の書き出し
  nxvp1c(ncdfid,cvname,mindex,cvalue)        : 1文字の書き出し
  nxvpnx(ncdfid,cvname,istart,icount,values) : 多変数の書き出し
  nxvpnc(ncdfid,cvname,istart,icount,cvalue) : 多文字の書き出し
  nxvpax(ncdfid,cvname,values)               : 変数まるごとの書き出し
  nxvpac(ncdfid,cvname,cvalue)               : 文字まるごとの書き出し
  nxvg1x(ncdfid,cvname,mindex,valuex)        : 1変数の読み出し
  nxvg1c(ncdfid,cvname,mindex,cvalue)        : 1文字の読み出し
  nxvgnx(ncdfid,cvname,istart,icount,values) : 多変数の読み出し
  nxvgnc(ncdfid,cvname,istart,icount,cvalue) : 多文字の読み出し
  nxvgax(ncdfid,cvname,values)               : 変数まるごとの読み出し
  nxvgac(ncdfid,cvname,cvalue)               : 文字まるごとの読み出し

  d. attributes

  nxaptx(ncdfid,caname,catype,naxlen,values) : 属性の書き出し
  nxaptc(ncdfid,caname,catype,naclen,cvalue) : 属性(文字)の書き出し
  nxagtx(ncdfid,caname,values)               : 属性の読み出し
  nxagtc(ncdfid,caname,cvalue)               : 属性(文字)の読み出し

ちょっとルーチンの数が多いようですが, 文字変数とそれ以外というのを区別
する必要があるために -----x と -----c の2系列があります. 

配列の取り扱いについては説明がいりますが, 書き出すと大変なので 7.5,
7.7 節あたりを読んで下さい. あるいは ncdtest.tar.Z にある具体例を見て
もらった方がいいかも知れません. 

ちょっとシリキレとんぼの解説となってしまいましたが, とりあえずこのくら
いにしておきます. 

塩谷
-- 
Masato Shiotani (NCAR, PO Box 3000, Boulder CO 80307 USA)
E-Mail:    [email-masked]  or  [email-masked]
Telephone: 303-497-1417           Fax: 303-497-1492