ISLSCP I CD-ROMからnetCDFファイルを作る

−Polcher氏作プログラムの解説と使い方−(under construction)

プログラマよALMAをめざせ


目次


はじめに

 ISLSCP−なんだか妙に発音しにくそうな略語です.これはInternational Satellite Land-Surface Climatology Projectの略で,少なくとも筆者の周りでは「いするすきぷ」と発音されています.

 ISLSCPについての詳しい説明は省略しまして(というか筆者も勉強不足),そのプロジェクトの成果物について紹介します.それはISLSCP Initiative data setsというものです.

 このデータセットは,世界中を緯度経度1度ずつに区切ったグリッドの各点(つまり東西360点×南北180点)について,1987年と1988年の2年間のいろいろな気象データの6時間ごとの値を示したものです.あっさり「いろいろな気象データ」と言ってしまいましたが,その内容は実に膨大なもので,CD-ROM版では5枚分となっています.

 このデータセットは,ALMAにとっても大変重要なものです.というのは,過去に行われた各種LSM相互比較プロジェクトでは,LSMへの「共通の」入力データとして,このデータセットが使われたことがあるのです(例:GSWP).つまり,いくつかのモデルに対して,ISLSCP Iという全く同じ境界条件を与えたときの挙動の差が解析されたのです.ある意味でモデル入力のグローバルスタンダードというわけで,使用事例が豊富なのです.ALMAは別にISLSCP Iに依存しているわけではありませんが,まずその第一歩としては入力にISLSCP Iを使って過去の結果と比較してみるという作業が不可欠だと考えられるのです.

 ISLSCP Iのデータフォーマットは単純なテキストです.というわけで,ALMAにあわせたLSMにこのデータを食わせるには,とりあえずこれをnetCDF化しなければなりません.これを実現するのがALMA関係者のPolcher氏が作ったiscscp2ncというプログラム・コマンド類です.


ファイル取得と解凍

 Polcher氏の作ったプログラムのWWW資料はhttp://www.ipsl.jussieu.fr/~ssipsl/data/data_islscp.htmlに用意されています.そこの中に,ソースファイルへのリンクが用意されています.まずはそれをとってきましょう.ファイル名はislscp2nc.tar.Zです.バージョンはよく分かりません(研究用プログラムでは,これは結構多い)が,更新日時は2000年5月15日と書いてあります.ALMA規約準拠のnetCDFを生成すると書いてあるので,ちょっと楽しみです.

 さて,まずはファイルを解凍しましょう.なお,ここではサブディレクトリを作る必要はありません.後のtarの実行の時にサブディレクトリislscp2ncが自動的に作られるからです:

% uncompress islscp2nc.tar.Z
% 

 ここでディレクトリの内容を見てみましょう.islscp2nc.tarというファイルができていればここまではOKです.次にこのtarファイルの内容を確認します:

% ls -alF
(中略)
-rw-r--r--   1 foo      group1     61440 Jul 15 19:31 islscp2nc.tar
(略)
% tar -tvf islscp2nc.tar
drwxr-xr-x 6072/3000      0 May 29 16:50 2000 ./islscp2nc/
-rw-r--r-- 6072/3000  17262 May 15 21:16 2000 ./islscp2nc/calendar.F90
-rwxr-xr-x 6072/3000    687 May 15 21:16 2000 ./islscp2nc/do_allfiles
-rwxr-xr-x 6072/3000    395 May 15 21:16 2000 ./islscp2nc/do_Europe
-rwxr-xr-x 6072/3000    386 May 15 21:16 2000 ./islscp2nc/do_Scan
-rw-r--r-- 6072/3000   1568 May 15 21:16 2000 ./islscp2nc/errioipsl.F90
-rw-r--r-- 6072/3000  26500 May 29 16:44 2000 ./islscp2nc/islscp2nc.F90
-rw-r--r-- 6072/3000    794 May 15 21:51 2000 ./islscp2nc/Makefile
-rw-r--r-- 6072/3000   3802 May 15 21:17 2000 ./islscp2nc/stringop.F90

 ここまでOKですか?では実際にファイルを取り出してみましょう.なお,このときカレントディレクトリの下にislscp2ncというファイルが自動的に作られます:

% tar -xvf islscp2nc.tar

x ./islscp2nc, 0 bytes, 0 tape blocks
x ./islscp2nc/calendar.F90, 17262 bytes, 34 tape blocks
x ./islscp2nc/do_allfiles, 687 bytes, 2 tape blocks
x ./islscp2nc/do_Europe, 395 bytes, 1 tape blocks
x ./islscp2nc/do_Scan, 386 bytes, 1 tape blocks
x ./islscp2nc/errioipsl.F90, 1568 bytes, 4 tape blocks
x ./islscp2nc/islscp2nc.F90, 26500 bytes, 52 tape blocks
x ./islscp2nc/Makefile, 794 bytes, 2 tape blocks
x ./islscp2nc/stringop.F90, 3802 bytes, 8 tape blocks

 これで解凍は終了です.といってもまだ前途は多難ですが…


メイク

 次にメイクを行います.普通はここでconfigureを行なうところなのですが,どうやらこのプロダクトは直接設定ファイルを書き換えさせる仕様のようです.まずは,上記のファイル解凍でできたディレクトリに移り,インストール法を説明したドキュメントを探してみましょう:

% cd islscp2nc
% ls -alF
(略)

 出てくるのはMakefile*.F90,それにいくつかのシェルスクリプト類だけのようです.つまり説明文書はありません.説明文書は,むしろ上記のWWW資料が中心のようです.そこを探すと,ありました.do_allfilesというシェルスクリプトを動かせとあります.このシェルスクリプトの内容を覗いてみると,冒頭が

# !/bin/csh
#
#

make islscp2nc

echo 'COMPILED'

/bin/rm -f CD_* *.log

なんていうことになっていて,つまりいきなりmakeを立ち上げている模様です.うーん大丈夫なのでしょうか.とりあえずMakefileの中を見てみます.幸いなことに,わずか32行です.チェックしたところ,アヤシイところはなさそうです.というわけで,早速makeを走らせ,帰ってきたメッセージに対処する作戦にでます.

% make clean
(エラーがいくつか出るが気にしない)
% make islscp2nd
/bin/cp errioipsl.F90 errioipsl.f90
pgf90  -c errioipsl.f90
sh: pgf90: not found
*** Error code 1
make: Fatal error: Command failed for target `errioipsl.o'

このエラーメッセージは気にしないわけには行きません.つまり,pgf90なんて命令は知らんよというメッセージです.これは名前からすると,Portland Group社製のFORTRAN90コンパイラです(プログラミング言語マニアならご存知かと思いますが,HPFですね).筆者のテスト環境(言い忘れましたが,SUN SPARC上のSolaris7,FORTRANコンパイラはSUN Workshop Compilers 4.2のf90です)ではpgf90なんてインストールされておらず,当然エラーとなるわけです.というわけでMakefile内の以下を書き換えます(しかしどうしてconfigureスクリプトが入っていないのだ?):

#F90         = pgf90
F90         = f90
RM          = /bin/rm
CP          = /bin/cp
(以下略)

 ただし,rmcpがそれぞれ/bin/rm/bin/cpに入っていない場合は上記の2行目や3行目も書き換える必要があります(やれやれ).では書き換えた後にもう一度挑戦です:

% make islscp2nd
/bin/cp errioipsl.F90 errioipsl.f90
f90  -c errioipsl.f90
/bin/rm errioipsl.f90
/bin/cp stringop.F90 stringop.f90
f90  -c stringop.f90
/bin/rm stringop.f90

お,何か上手くいっているようです.しかし,結局またダメになってしまうのでした:


  INCLUDE "netcdf.inc"
cf90-63 f90comp: ERROR ISLSCP2NC, File = islscp2nc.f90, Line = 58
  Cannot open INCLUDE file "netcdf.inc".
(中略)
f90: SunSoft F90 Version 1.0.1.0  (21229283) Tue Jul 18, 2000  14:56:47
f90: COMPILE TIME 0.620000 SECONDS
f90: MAXIMUM FIELD LENGTH 2590320 DECIMAL WORDS
f90: 856 SOURCE LINES
f90: 16 ERRORS, 1 WARNINGS, 0 OTHER MESSAGES, 0 ANSI
f90: CODE: 1216 WORDS, DATA: 25 WORDS
*** Error code 1
make: Fatal error: Command failed for target `islscp2nc.o'

大量のエラーが出てきましたが,こういうときに見るべきなのは最初に発見されたエラーです(最初の不具合をつぶすと,後に続くエラーメッセージが皆消えてしまうというのはよくあることです).それはCannot open INCLUDE fileというメッセージですから,インクルードファイルが見当たらないという意味だとわかります.そのファイル名はnetcdf.inc.明らかにnetCDF用のインクルードファイルです.FORTRANコンパイラが,このファイルの存在を最初から知っているわけがありませんから,これはユーザが明示的に位置を教えてやる必要があります.これには環境変数を用いる方法もありますが,ここでは直接Makefileを書き換える手段にでます.

 netCDFのライブラリやインクルードファイルがどこに入っているのか(それ以前に,そもそも入っているのか)はホストの管理者に聞いてみてください.以下ではその位置(ディレクトリ)を/usr/local/netcdfと仮定します.この場合,netCDF用のインクルードファイルは/usr/local/netcdf/includeに入ります.

 FORTRANコンパイラ,というかコンパイラ一般にいえることですが,インクルードファイルを探す場所の指定には-Iオプションを使うのが普通です.つまり,f90命令に,-I/usr/local/netcdf/includeオプションをつけるわけです.そういう風にMakefileを書き換えます:

NETCDFHOME = /usr/local/netcdf

F90         = f90
RM          = /bin/rm
CP          = /bin/cp
FLAGS       = -I$(NETCDFHOME)/include
F_LOAD      = -Wl,-Bstatic

(後略)

Makefileでは,後に「F90」(現在の例の場合,f90)の指定に「$(FLAGS)」という変数を含めています.普通は,このFLAGSという変数に,「F90」に与えるオプションを書き入れます.それが上記の「FLAGS = ...」という行です.ただしFLAGSの定義に直接/usr/local/netcdf/includeを書き込まずに,ちょっと間接的に,別に定義したnetCDFホームディレクトリ用変数NETCDFHOME(=/usr/local/netcdf)を用いています.これはNETCDFHOMEは別のところでも使う可能性があり(実際,後で出てきます),netCDFのホームディレクトリをそのたびに書くのは面倒だし,後での変更も大変になるからです.

 それではもうメイク可能になるでしょうか?

% make islscp2nc
(略)
f90 -o islscp2nc errioipsl.o stringop.o calendar.o islscp2nc.o 
-Wl,-Bstatic -L/distrib/local/netcdf/pgf/lib/ -lnetcdf
f90: Warning: Option -Wl,-Bstatic passed to ld, if ld is invoked, ignored otherwise
/usr/ccs/bin/ld: illegal option -- W
/usr/ccs/bin/ld: illegal option -- W
(中略)
*** Error code 1
make: Fatal error: Command failed for target `islscp2nc'

ハイ残念でした.しかし一歩前進です.というのは,細かい点は省略しますが,コンパイルはすべて終わり,リンクの段階に入っていることがわかるからです(リンクの段階といえば,もう実行プログラムの完成一歩手前です).で,上記のメッセージは,f90というコマンドが「-Wl,-Bstatic」なんてコマンドを知らないので別のコマンドld(これはリンクを行うコマンドです)にそのオプションを横流しすると言っています.そして,ldのほうは,オレだってそんなオプションは知らんとエラーを返してきているのです.なお,Makefile内では,リンクに使うオプションは変数F_LOADに入っています.

「-Wl」はコンパイラ依存が強いオプション(-Bstaticという文字列をldに横流しする指令と思われますが未確認)で,f90では用意されていません.一応は削除します.「-Bstatic」はごく普通なので残します.これでうまくいくでしょうか.実はダメなのです.

NETCDFHOME  = /usr/local/netcdf

F90         = f90
RM          = /bin/rm
CP          = /bin/cp
FLAGS       = -I$(NETCDFHOME)/include
F_LOAD      = -Bstatic
% make islscp2nc
f90 -o islscp2nc errioipsl.o stringop.o calendar.o 
islscp2nc.o  -Bstatic -L/distrib/local/netcdf/pgf/lib/ -lnetcdf
ld: fatal: library -lnetcdf: not found
ld: fatal: File processing errors. No output written to islscp2nc
*** Error code 1
make: Fatal error: Command failed for target `islscp2nc'

何が起こったのでしょうか.これは上の強調表示部分に示した「-L/distrib/local/netcdf/pgf/lib/ -lnetcdf」の部分,特に後半が問題なのです.「-L」オプションはリンクの際に組み込むライブラリの場所(ディレクトリ),「-l」オプションはライブラリの名前を指定するものです(上記ではnetCDF関係のライブラリを組み込もうとしていることは明白でしょう).しかし,上記でしていている-L/distrib/local/netcdf/pgf/lib/なる場所には探しているnetCDFライブラリなどないのです(そもそもこんなディレクトリはこちらの環境にはありません).「-L」オプションをこちらの環境に合わせて書き換える必要があります.

 また,「-L」にせよ「-l」にせよ,リンクのオプションは変数F_LOADに入れる構造になっていると見るのが普通です.以上を考えると,Makefileは次のような構造になるはずです.

NETCDFHOME  = /usr/local/netcdf

F90         = f90
RM          = /bin/rm
CP          = /bin/cp
FLAGS       = -I$(NETCDFHOME)/include
F_LOAD      = -Bstatic -L$(NETCDFHOME)/lib -lnetcdf

islscp2nc : errioipsl.o stringop.o calendar.o islscp2nc.o
        $(F90) -o islscp2nc errioipsl.o stringop.o \
         calendar.o islscp2nc.o  $(F_LOAD)
(後略)
% make islscp2nc
f90 -o islscp2nc errioipsl.o stringop.o calendar.o islscp2nc.\
   -Bstatic -L/usr/local/netcdf/lib -lnetcdf
% ls -alF islscp2nc
-rwxr-xr-x   1 foo      group1   7708872 Jul 18 15:43 islscp2nc*
%

ちゃんとmakeは終わったようです.islscp2ncという実行ファイルもできています.お茶でも飲んで一息入れましょうか.


あれこれ手直し

もしヒマがあればMakefileについて,次のような手直しをすると精神衛生上いいかもしれません.現行のMakefileで問題ないと思う方は別にいいのですが…

  1. make cleanで消去されるファイルの名前は実はコンパイラ毎に微妙に違います.デフォルトでは*.o *.f90 *.mod islscp2ncが消去されることになっていますが,このうち*.modがコンパイラ依存名なのです.この点を設定できるように,消すべきファイルのリストを変数に入れ,また,ファイルがなかったときのエラーメッセージを抑制するために,rm命令に-fオプションをつけます.
     
  2. allターゲットもつけましょう
     
  3. このメイクファイルでは,*.F90というソースファイルを*.f90にコピーし,そのファイルをコンパイルし,コンパイル後に*.f90を消去するという方法をとっています.つまり形式的には,*.F90から*.oを生成しています.しかもこれは対象となっている*.F90ファイルのすべてについて同じ操作を行っています.
    これなら,各ファイルごとにメイクルールを書くのではなく,「*.F90から*.oを作る暗黙のルール」を設定したほうがよほどすっきりするし,後でのメンテナンスも楽になります.

以上の変更を加えたMakefileを以下に示します:

#
# Makefile for islscp2nc
#                Originally made by Dr. Polcher
#                http://www.ipsl.jussieu.fr/~ssipsl/data/data_islscp.html
#                2000-May-15 version
#
#                Revised by AGATASHI
#
#                  2000-Jul-18 version 1.1

NETCDFHOME  = /usr/local/netcdf

F90         = f90
RM          = /bin/rm
CP          = /bin/cp
FLAGS       = -I$(NETCDFHOME)/include
F_LOAD      = -Bstatic -L$(NETCDFHOME)/lib -lnetcdf
CLEANFILES  = *.f90 *.M *.o islscp2nc

.SUFFIXES : .F90 $(SUFFIXES)

.F90.o:
        $(CP) $< $*.f90
        $(f90) $(flags) -c $*.f90
        $(rm) $*.f90

all : islscp2nc

islscp2nc : errioipsl.o stringop.o calendar.o islscp2nc.o
        $(F90) -o islscp2nc errioipsl.o stringop.o calendar.o islscp2nc.o  $(F_LOAD)

clean :
        $(RM) -f $(CLEANFILES)

*.F90ファイルについてのルールを一つ一つ書いているのではないことに注目してください.

 注記1:とりあえず今はオプティマイズについては触れないでおきます.

 注記2:実は上記のメイクファイルは完全ではありません.各*.o*.F90との間にも微妙な依存関係があるからです.gmakeにおける-jオプションやSUNのdmakeコマンドのように並列メイクを行なう場合に問題が起きることがあります.しかし並列メイクのような凝ったことをするほどのサイズのプログラムではありませんから,そのままにしておきます.


実行しながらソースを改造

 では今や実行可能となったislscp2ncコマンドを動かしてみましょう.するとWWW資料にあるようにいろいろ聞いてきますので,とりあえず答えてみます:

% ./islscp2nc
 Month to start the transfer (in yymm) (Starting the first day of the month)  :
8701
 Month to end the transfer (in yymm) (Ending the last day of the month) :
8701
 Path in which the ISLSCP files are to be found :
/export/islscp
 Path to which the netCDF files should be written :
.
 Should the data be stored only over land points [y/n] ?
n
 File name for the netCDF file to be created :
firsttest
 Longitude interval to be written to the file (lon_min, lon_max):
0 180
 Latitude interval to be written to the file (lat_min, lat_max):
-90 90
 The netCDF that will be created :./firsttest.nc
 BEGIN : yy, mm, dd :1987,  1,  1
 END : yy, mm, dd :1987,  1,  31
 >>>>>>>>>>>>> ibeg, imr :180,  180
 >>>>>>>>>>>>> jbeg, jmr :1,  179
 DOING :87010100
cp: cannot access /export/islscp/cdrom3/y87m01/temp_2m/t7010100.z
cp: cannot access /export/islscp/cdrom3/y87m01/dwpnt_2m/d7010100.z
cp: cannot access /export/islscp/cdrom4/y87m01/mwnd_10m/w7010100.z
cp: cannot access /export/islscp/cdrom4/y87m01/sur_prsr/p7010100.z
cp: cannot access /export/islscp/cdrom5/y87m01/ecm_lang/hyb_lwdn/l7010100.z
cp: cannot access /export/islscp/cdrom5/y87m01/ecm_lang/hyb_swdn/s7010100.z
cp: cannot access /export/islscp/cdrom5/y87m01/nmc_gpcp/totl_prc/o7010100.z
chmod: No match.
uncompress: No match.

lib-1001 : UNRECOVERABLE library error


Encountered during a list-directed READ from unit 11
Fortran unit 11 is connected to a sequential formatted text file:
  "CD_dwpnt_2m"
Abort

 はい見事にコケました.これは次のようなことが原因です:

  1. WWW資料にあるように, ISLSCPデータはどこかのディレクトリのサブディレクトリとしてcdrom3,cdrom4,cdrom5を作って,その中に入れるということになっています.ところが前もって分かっているならともかく,特にもうISLSCPがHDDに入っているという場合は全く違ったディレクトリ名になっていたりします(上のログでもそうでした)
     
  2. ログにuncompressという文字列があることから分かるように,islscp2ncは内部的にUNIXコマンドuncompressを動かしています.これは上記の名前決め打ちディレクトリ内にはISLSCP CD-ROMの内容,つまりcompressで圧縮されたファイルがそのまま入っていると仮定しており,それを解凍しようと試みていることを示しています.ところが,ISLSCPのデータを,解凍した形でディスクに保存している例もあります.この場合圧縮ファイル(ファイル名は*.Zとなる)が見つからず,エラーになります.
     
  3. CD-ROMをどのファイルシステムとしてマウントしたかで,CD-ROM内のファイル名が変わってきます.正確に言うと,全部大文字か全部小文字になってしまいますが,それは統一されているわけではありません.オリジナルのislscp2nc.F90では全部小文字と決め打ちしています.

 今回は最初の方だけで引っかかりましたが,これを回避しても2,3番目でまた引っかかるのは明白です.この対象となるコード部分はislscp2nc.F90の217〜236行,ならびに566〜649行にあります:

    !
    !
    !  Get cdrom files and uncompress them
    !
    !
    WRITE(str_yy,'(I2.2)') year-1900
    WRITE(str_mm,'(I2.2)') month
    WRITE(str_dd,'(I2.2)') day
    WRITE(str_hh,'(I2.2)') hour
    !
    WRITE(*,*) 'DOING :', str_yy,str_mm, str_dd, str_hh
    !     temp_2m
    !     K
    command='cp '//in_path(1:LEN_TRIM(in_path))//'cdrom3/y'// str_yy//'m'//str_mm//&
       & '/temp_2m/t'//str_yy(2:2)//str_mm// str_dd//str_hh//'.z CD_temp_2m.Z'
    iout = system(command)
(中略)
    !  Get the right permissions
    iout = system('chmod 644 CD_*.Z')
    !     Uncompress
    iout = system('uncompress CD_*.Z')
(中略)
    OPEN (11, file='CD_dwpnt_2m')
    READ(11,*) dewt
    CLOSE(11)

 さて,これに対する対策はいくつか考えられます.まずはパスおよびファイル名に関する方策を挙げてみましょう:

こちらの状況に合わせてコードに書いてあるファイル名を書き換えてしまう
ハードコード路線踏襲というわけで,もっとも原始的な方法です.これだと,コード変更は私たちの設定でしか有効ではありませんから,あまりやりたくはありません.しかし時間に追われた場合には有効ではあります(笑).
 
パスに関しては,シンボリックリンクでcdrom3等といったディレクトリを作ってしまう
これまた原始的ではありますし,ユーザに負担を強いるものではあります.しかしコードは単純になりますし,ツブシが効きます.
 
プログラムが聞いてくる項目の中にファイル名等も含める
一見スマートでよさそうな計画.しかし障害はあります.実は作者Polcher氏のサイトにはislscp2ncを利用したシェルスクリプトがいくつか用意されており,それらは当然islscp2ncが聞いてくる項目が変わるとそれに応じて変更しなければなりません.
 
コマンドラインオプションでファイル名などを与える
デフォルトの値は現在ハードコードされているものにして,site specificな設定をコマンドラインから与える方法です.これも実はシェルスクリプトの変更を要します.
 
設定を環境変数で与える
コマンドラインと同様に環境変数を使う方法も考えられます.
 
別に設定ファイル(islscp2nc.confかな?)を置き,その中に設定を格納する
大掛かりなプログラムではよくある方法です.しかし今回はそこまでやる必要があるかどうか…
 
パスは上記のいずれかの方法で与えるとして,ファイル名の大文字小文字の別や圧縮の有無は自動認識させる
これが最も汎用的です.ファイル探索命令を使いこなせれば大丈夫でしょうが,コードは複雑になりがちです.
 

(ここまで,2000/07/28までに記)

 で結局採用した「仕様」は以下のとおりです:

  1. 面倒だが,ディレクトリ名cdrom3,cdrom4,cdrom5はハードコードのままとする.違うディレクトリにすでにインストールしてある場合は,シンボリックリンクを張る.
     
  2. ファイル名が全大文字でも全小文字でも,また圧縮してあっても(ファイル名が*.zまたは*.Z)していなくても対応できるようにする.つまり大文字小文字/圧縮非圧縮に対応して全部で4通りのファイル名の可能性があるが,その4つの可能性についてすべてファイルの存在を調べることにする
     
  3. 圧縮ファイルが見つかった場合は,カレントディレクトリに展開して読み込む.非圧縮(解凍済み)の場合はそのファイルを直接読み込む.
     
  4. 上記の変更により,islscp2ncコマンドに与えるキーボード入力パラメタはオリジナルと変わらない.
     

 大文字小文字の変換は,FORTRANでは標準で用意されてはいないですから,自分で作るか人のものを借りてくるかしかありません.ちょうど,このプログラムのアーカイブの中にあるstringop.F90に文字列関係の関数がたくさん用意されているのでそれを流用できそうです.探してみると,ありました.こんなソースです:

 SUBROUTINE struppercase(str)
    !
    !   Transforms a string into uppercase
    !
    IMPLICIT NONE
    !
    CHARACTER*(*) :: str
    !
    INTEGER :: i,ic
    !
    DO i=1,LEN_TRIM(str)
      ic = IACHAR(str(i:i))
      IF ( ic .GE. 97 .AND. ic .LE. 122 ) THEN
          str(i:i) = CHAR(ic-32)
      ENDIF
    ENDDO
    !
 END SUBROUTINE struppercase

ところがこれは移植性に問題アリです.文字コードがASCIIならいいけどEBCDICならどうなのでしょう?結局次のようなルーチンを自作しました.動作は遅いでしょうがしょうがないです:

 !
  ! UCASE : change lower letters to upper ones
  !

CHARACTER*(*) FUNCTION UCASE(str_org)
  CHARACTER*(*)  str_org
  CHARACTER (LEN=26) :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  CHARACTER (LEN=26) :: lower = 'abcdefghijklmnopqrstuvwxyz'

  INTEGER :: pos
  INTRINSIC LEN_TRIM,INDEX

 UCASE = str_org

  DO i=1,LEN_TRIM(UCASE)
    pos=INDEX( lower , UCASE(i:i))
    IF (pos > 0) UCASE(i:i) = upper(pos:pos)
  END DO
END FUNCTION UCASE

FORTRANを使うのは久しぶりなので何か妙な言い回しが多いかもしれないですがご容赦ください.

(ここまで2000/08/04記)

(以下続く.結局I/O部分を全面的に書き換え,SUNのFORTRAN90 1.2(Worksho4.2)の信じがたいほどオバカなバグに悩まされながらも現在は動作に成功.最適化・並列化なしですと,1年分全球のデータを作るのに約2時間,ファイルアクセスをチューニングして1時間30分弱,さらに最適化オプションを調整してして約53分といったところです.もうすこし速くしたいですね.時間を見つけて細かい調整日記を書くので請うご期待!)