GrADSスクリプトのTips
はじめに
-
以下のコンテンツは、2014年3月時点における東北大学大学院理学研究科 流体地球物理学講座のページを、web管理者の許諾を得てコピーしたものです。
- 従って、以下のコンテンツは講座メンバーをはじめ様々な方々の協力・助言・激励によって作成されたものです。
- 今のところ情報は古いままですが、講座ページとは独立して今後少しずつ更新を行う予定です。
- 講座ページとは適宜同期を行うなど、今後も協力関係を保って行けたらと思います。
- 内容に間違いがありましたら、小玉 までご連絡ください。
目次
- はじめに
- 目次
- 基本
- 表示
- 変数
- 条件分岐
- 繰り返し
- 演算子
- 組み込み関数
- 三角関数を計算する
- 自然対数を計算する
- 常用対数を計算する
- 指数関数を計算する
- 指数関数(exp)を計算する
- 平方根を計算する
- 絶対値を計算する
- 余りを計算する
- 余りの整数部分を計算する
- 小数を最も近い整数に直す
- 小数を整数に直す(切捨て)
- 文字列が整数か実数かを調べる
- 文字列の長さを得る
- 数値を整形する
- 文字列を取り出す
- 行を指定して文字列を取り出す
- 空白で区切られた文字列から、n番目の文字列を取り出す
- 空白で区切られた文字列から、n番目の文字列の位置を取得する
- テキストファイルの読み込み
- テキストファイルの書き込み
- ファイルのクローズ
- 自作の関数
- デフォルトのスクリプト
- 応用例
- その他
- 自作したスクリプトファイルはどこに置くべきか
- 自作した関数を別ファイルにするには
- スクリプトを明示的に終了する
- バグ:NetCDFファイルとGridファイルは同時に開けない。
- バグ:"e"と"+"の区別ができない(1.8系、1.9系)
- Link
基本
スクリプトを実行する
スクリプトを実行するには GrADsのrunコマンドを使います。
run ファイル名 [引数]
ただし引数は省略可能です。以下にスクリプトの例を示します。 1行目のコントロールファイル名と 2行目の変数名を適当なものに変更し、 test1.gsという名前で保存して実行してください。
test1.gs
'open wind.ctl' 'd u'
実行例
ga-> run test1.gs ga->
これで画面に絵が表示されます。もし何も表示されない場合は、 test1.gsの 'd u' の後に改行が入っているかどうか確かめてみてください。 GrADsスクリプトでは末尾に改行が入っている行のみ実行されます。
GrADsスクリプトの拡張子(ファイル名の . の後の文字)は、ふつう gs (grads scriptの略) とします。 runの際には.gsを省略することができ、
ga-> run test1
でも上と同じように実行できます。ちなみにrunも省略可能で、
ga-> test1
でも動きます。
スクリプトの中身は、実行したいGrADsコマンドをシングルクオーテーション' 'で囲んで並べます。ダブルクオーテーション" "でも構いません。スクリプトを実行すると、上から順にコマンドが実行されていきます。
文法上は必ずしもコマンドを ' ' で囲む必要はありません。しかし、' 'で囲まないとスペースが無視されてしまいます。したがって、
test_good.gs
q
であればうまく動きますが、
test_bad.gs
q file
では
ga-> run test_bad.gs Unknown command: qfile ga->
とエラーが出ます。したがって、GrADsコマンドは全て' 'で囲むようにしたほうが良いでしょう。
行をコメントアウトする
コメントにしたい行の先頭(1桁目)に * をつけると、その行は無視されます。
'set lev 100' *'set lev 1000'
必ず行の先頭に*をつけて下さい。 *の前に空白やタブが入っていても、エラーになります。
一行に複数のコマンドを記述する
";"で区切ると一行に複数のコマンドを記述することができます。
-
例
'set lev 1000 1' ; 'set lat 50' ; 'set lon 135'
表示
文字列を表示する
say '文字列' prompt '文字列'
sayは文字列を表示して改行しますが、promptは改行しません。
-
(例)"Hello GrADS" と表示して改行する
say 'Hello GrADs'
変数
変数を使う
変数名=値
スクリプト内では文字列変数を扱うことができます。変数名は1〜8文字のアルファベット又は数字を使うことができますが、1文字目は必ずアルファベットにします。
-
(例)文字列"Eliassen Palm"を変数EPに格納する
EP='Eliassen Palm'
-
(例)10.5をUに代入する
U=10.5
上のように、数値を代入する場合はクオーテーションを付ける必要はありません。
変数の内容を表示する
say 変数名 prompt 変数名
-
(例)文字列"Hello"を変数に格納して表示する
word='Hello' say word
-
(例)変数の内容と文字列を混ぜて表示する
name='ABC' value=10 say 'name='name' value='value
配列を使う
変数名の末尾を".数字"とすることで、配列的に変数を扱うことができます。
-
(例)配列aを使う
i = 1 while( i <= 10 ) a.i = i * i say a.i i = i + 1 endwhile say a.3
ちなみに.の後は数字以外でも構いません。この場合は配列というよりhash変数的ですね。ただし、
a.red = 10 say a.red
のように直接使用することはできません。
color = 'red' a.color = 10 say a.color
のように.の後を必ず変数にする必要があります。
なお、配列をたくさん取りすぎるとスクリプトがすごく重くなります。
i = 1 while( i < 100000 ) a.i = i * i i = i + 1 endwhile
のようなスクリプトはお薦めできません。この処理だけでなく、この後の処理も非常に遅くなります。
コマンドの結果を表示する
say result
d や q dims などをスクリプト内に記述しても、コンソールには何も表示されません。本来表示される内容は、特殊変数resultに格納されます。
-
(例)uを描画する(直接入力した場合と同じメッセージも表示)。
'd u' say result
条件分岐
条件によって処理を分岐する
-
(1)
if(条件式) 処理 ・・・ endif
-
(2)
if(条件式) 処理 ・・・ else 処理 ・・・ endif
条件処理にはif〜else〜endifを使います。else〜は省略可能ですが、endifは必ず付けて下さい。 なお、else ifに相当する文法はありません。
-
(例)ifを使った処理(この例では "Good morning" と表示される)
switch=2 if(switch=1) say 'Hello' else say 'Good evening' endif
-
(例)ifを使った処理(文字列でも条件分岐ができる例)
season='DJF' if(season='DJF') say 'DJFです' endif if(season='JJA') say 'JJAです' endif
繰り返し
while文
while(条件式) 処理 ・・・ endwhile
-
(例) t=1〜3までのUを重ねて表示する
i=1 while(i<=3) 'set t 'i 'd u' i=i+1 endwhile
whileループから脱出する
break
whileループの先頭に処理を移す
continue
演算子
一覧表
優先順位 | 演算子 | 意味 |
---|---|---|
1 | - | マイナス符号(単項演算子) |
! | 否定(単項演算子) | |
2 | 除算 | |
* | 乗算 | |
3 | + | 加算 |
- | 減算 | |
4 | % | 連結 |
5 | = | 等しい |
!= | 等しくない | |
> | 大なり | |
>= | 大なり又は等しい | |
< | 小なり | |
<= | 小なり又は等しい | |
6 | & | 論理AND |
7 | | | 論理OR |
-
(例)a=1またはb=1のときYesと表示する
if(a=1 | b=1) say 'Yes' else say 'No' endif
組み込み関数
- スクリプト用の組み込み関数。
- 引数としてスクリプト内で定義した文字列変数を与えることはできます。しかし(次元を持った)所謂GrADS変数を与えることはできませんのでご注意下さい。GrADS変数の場合はGrADS関数(ave, sinなど)を使ってください。
- 組み込み関数には"Intrinsic Functions"と"Math Functions"があります(違いはよく分かりませんが)
-
Intrinsic Functions の一覧
- strlen, sublin, subwrd, substr, read, write, close
三角関数を計算する
ret = math_sin(angle) ret = math_cos(angle) ret = math_tan(angle) ret = math_asin(angle) ret = math_acos(angle) ret = math_atan(angle) ret = math_atan2(angle, angle2) ret = math_sinh(angle) ret = math_cosh(angle) ret = math_tanh(angle) ret = math_asinh(angle) ret = math_acosh(angle) ret = math_atanh(angle)
angle | 角度(ラジアン) |
angle2 | 角度(ラジアン) |
ret | angle(math_atan2の場合はangle/angle2?)の三角関数 |
自然対数を計算する
ret = math_log(num)
num | 0より大きな任意の数 |
ret | numの自然対数 |
常用対数を計算する
ret = math_log10(num)
num | 0より大きな任意の数 |
ret | numの常用対数 |
指数関数を計算する
ret = math_pow(num, exponent)
num | 任意の数 |
exponent | 任意の数 |
ret | 指数関数の値(num^exponent) |
指数関数(exp)を計算する
ret = math_exp(exponent)
exponent | 任意の数 |
ret | 指数関数の値(exp^exponent) |
平方根を計算する
ret = math_sqrt(num)
num | 任意の数 |
ret | numの平方根(ルート) |
絶対値を計算する
ret = math_abs(num)
num | 任意の数 |
ret | numの絶対値 |
余りを計算する
ret = math_fmod(num1, num2)
num1 | 小数 |
num2 | 小数(非0) |
ret | num1/num2の余り |
余りの整数部分を計算する
ret = math_mod(num1, num2)
num1 | 小数 |
num2 | 小数(非0) |
ret | num1/num2の余りの整数部分 |
小数を最も近い整数に直す
ret = math_nint(num)
num | 小数 |
ret | numに最も近い整数値(恐らく[num+0.5]) |
小数を整数に直す(切捨て)
ret = math_int(num)
num | 小数 |
ret | numの小数部分を切り捨てた整数値([num]) |
文字列が整数か実数かを調べる
ret = valnum(文字列)
-
戻り値(ret)
0 文字列は実数ではない 1 文字列は整数である 2 文字列は整数ではないが実数である
文字列の長さを得る
ret = math_strlen(string) ret = strlen(string)
string | 文字列 |
ret | 文字列の長さ |
- strlen()はVersion1.8以下では使えない?
数値を整形する
ret = math_format(format, num)
format | C言語風の書式指定(e.g., %5.2f, %+10.5e) |
num | 整形する数値 |
ret | 整形された数値 |
-
(例)小数点第1位まで表示
pi = 3.141592 a = math_format('%.1f', pi) say a
-
(例)小数点第1位まで表示(全部で10桁になるように左側に空白を入れる)
pi = 3.141592 a = math_format('%10.1f', pi) say a
-
(例)符号を必ず付けて表示
pi = 3.141592 a = math_format('%+10.3f', pi) say a
文字列を取り出す
ret = substr(string, start, length)
string | 文字列 |
start | 整数値(開始位置)>0 |
length | 整数値(長さ) |
ret | 指定した文字列 |
- stringが短すぎる場合、NULL("")が返ります。
行を指定して文字列を取り出す
ret = sublin(string, n)
string | 文字列 |
n | 整数値 |
ret | n行目の文字列 |
- stringの行数がnより小さい場合、NULL("")が返ります。
空白で区切られた文字列から、n番目の文字列を取り出す
ret = subwrd(string, n)
string | 文字列 |
n | 整数値 |
ret | n番目の文字列 |
- stringが短すぎる場合、NULL("")が返ります。
空白で区切られた文字列から、n番目の文字列の位置を取得する
ret = wrdpos(string, int)
string | 文字列 |
int | 整数値 |
ret | n番目の文字列の開始位置 |
テキストファイルの読み込み
ret = read(filename)
retには2行の情報が返される。1行目がファイル状態、2行目にファイルの内容である。~ ファイル状態は「0」で正常、「1」でエラー、「2」でファイルの最後まで来ています、などとなる。~ 一度のreadで1行分の情報しか読み取らないために、複数の行を読み取りたい場合は、複数回実行する必要がある。~ 以下サンプル。
(test.dat) this data is test.dat 1.0 2.0 3.0 4.0 5.0 6.0
(サンプルスクリプト) ret = read('test.dat') a = sublin(ret,1) b = sublin(ret,2) say 'a is 'a say 'b is 'b ret = read('test.dat') a = sublin(ret,1) b = sublin(ret,2) say 'a is 'a say 'b is 'b
(結果) a is 0 b is this data is test.dat a is 0 b is 1.0 2.0 3.0
テキストファイルの書き込み
ret = write( filename, record ) <- 上書き ret = write( filename, record, append ) <- 追記
appendを指定しない場合、最初のwriteで元のファイルが消えてしまうので注意が必要です。書き込みに成功すると0、失敗すると1又は8が返されます。
ファイルのクローズ
ret = close( filename )
writeで書き込んだファイルをreadで読む場合など、明示的なファイルのクローズが必要な場合に用います。
自作の関数
- スクリプト用の自作関数。
使いかたは組込み関数と基本的に同様ですが、使用前に
rc = gsfallow("on")
を実行しておく必要があります。
関数の作成
function 関数名(引数1, 引数2, ...) ... return 戻り値
引数や戻り値は省略できます。
デフォルトのスクリプト
cbar.gs, cbarn.gs, cbarc.gs
カラーバーを表示する。「set gxout shaded」のときのみ有効。
ga-> cbar //長方形 ga-> cbarn //基本的に上と同じ、但し端が三角 ga-> cbarc //隅に小さく
font.gs
font set に含まれる全てのフォントを表示する
ga-> font
zoom.gs
マウスでクリックした範囲をズームする。 LAT-LON図でのみ有効。
ga-> d u //2次元の図を描画しておく ga-> zoom click right botton .. to clear any previous mouse clicks click on bottom left corner of zoom area click on top right corner of zoom area ga-> d u //ズーム領域を描画
応用例
図の日付を描画する
set time (またはset t)で設定した日付を図中に入れます。
'set time 01jan2000' 'q dims' // 次元の情報を変数resultに格納 temp=sublin(result,5) // 日付を表す行を取り出す tim=subwrd(temp,6) // 日付を表す部分を取り出す 'set strsiz 0.2 0.2' // 文字の大きさを設定 'draw string 2.0 2.0 'tim // 描画
ある物理量の最大値・最小値をファイルに保存する
T(温度)の最大値・最小値を画面に出力し、ファイル(t_minmax.txt)に保存します。スクリプトの中で有効。
'set gxout stat' // 統計量を出力 'd t' // 温度の出力 res=sublin(result,8) // 最大値・最小値の行(この場合、8行目)を取り出す min=subwrd(res,4) // 最小値(この場合、4行目)を取り出す max=subwrd(res,5) // 最大値(この場合、5行目)を取り出す say 'min/max:'min' 'max // 画面に取り出した最小値・最大値を出力 dum=write(t_minmax.txt,min' 'max) // ファイル(t_minmax.txt)に最小値・最大値を保存
その他
自作したスクリプトファイルはどこに置くべきか
ga-> run test
を実行すると、GrADSは以下の順番でスクリプトを実行しようとします。
- 現在のディレクトリのtest
- 現在のディレクトリのtest.gs
- 環境変数GASCRPで指定したディレクトリのtest
- 環境変数GASCRPで指定したディレクトリのtest.gs
何度も使わないスクリプトであれば、好きな場所に置いてそこからGrADSを実行するとよいでしょう。汎用性のある(=何度も使う)スクリプトの場合は、GASCRPで指定したディレクトリに置くのがよいでしょう。好きな場所に置いて絶対パスでディレクトリを指定することも可能ですが、入力が面倒になります。
なお、GASCRPはスペース区切りで複数指定することが可能です。たとえば
GASCRP="/usr/local/lib/grads /home/hoge/myscripts"
のように、デフォルトのスクリプトと自作のスクリプトを分ける使い方が考えられます。
自作した関数を別ファイルにするには
同一ファイルに存在しない関数(たとえばmyfunc())は、
- 呼出元のスクリプトがあるディレクトリのmyfunc.gsf
- 環境変数GASCRPで指定したディレクトリのmyfunc.gsf
の順に関数が入ったファイルを探します。また、スクリプト内でgsfpath()関数を使って指定することも可能です。例えばgsfpath("aaa bbb")と予め指定すると、
- 呼出元のスクリプトがあるディレクトリのmyfunc.gsf
- 呼出元のスクリプトがあるディレクトリのaaa/myfunc.gsf
- 呼出元のスクリプトがあるディレクトリのbbb/myfunc.gsf
- 環境変数GASCRPで指定したディレクトリのmyfunc.gsf
となります。
ここからは経験則ですが、gsfpath を複数回実行すると、以前に gsfpath で設定したパスは原則として上書きされます。但し、一度でも実行された関数は gsfpath の設定値が変わっても実行可能です。また、gsfpath で設定するパスは呼び出し元の gs から見たパスを設定します。以上を例で分かりやすく説明すると、
-
dir1/func1.gsf
function func1() return 'func1 in dir1'
-
dir1/func2.gsf
function func2() return 'func2 in dir1'
-
dir2/func1.gsf
function func1() return 'func1 in dir2'
-
dir2/func2.gsf
function func2() return 'func2 in dir2'
-
test1.gs
rc = gsfallow('on') rc = gsfpath('dir1') say func1() say func2()
-
test2.gs
rc = gsfallow('on') rc = gsfpath('dir1') say func1() rc = gsfpath('dir2') say func1() say func2()
というファイルを用意しておき、test*.gs をそれぞれ実行すると、
ga-> test1 func1 in dir1 func2 in dir1 ga-> test2 func1 in dir1 func1 in dir1 func2 in dir2
となります。さらに追加で
-
dir1/func3.gsf
function func3() rc = gsfpath('dir2') say func2() return 'func3 in dir1'
-
dir1/func4.gsf
function func4() rc = gsfpath('../dir2') say func2() return 'func4 in dir1'
-
test3.gs
rc = gsfallow('on') rc = gsfpath('dir1') say func3() say func1()
-
test4.gs
rc = gsfallow('on') rc = gsfpath('dir1') say func4() say func1()
を用意すると、
ga-> test3 func2 in dir2 func3 in dir1 func1 in dir2 ga-> test4 Function not found: func2 Error occurred on line 3 In file dir1/func4.gsf Error occurred on line 3 In file test4.gs
となり、gsf ファイル内で呼び出す gsfpath は呼び出し元の gs から見たパスを指定する必要があることが分かります。
スクリプトを明示的に終了する
exit
スクリプトファイルの終端に達する前に動作を終了します。
-
(例)Uのみ描画する
'd U' exit 'd V'
exitはスクリプトのデバッグに重宝します。
バグ:NetCDFファイルとGridファイルは同時に開けない。
open ***.grd sdfopen ***.nc
- の後、ある変数を描画しようとすると、「セグメンテーション違反です」と警告が出て異常終了する。
バグ:"e"と"+"の区別ができない(1.8系、1.9系)
if( 'e' = '+' ) ; say 'fail' ; endif
というスクリプトを実行すると、failと表示されます。つまり、"e"と"+"は条件分岐で区別できません。このバグは2.0系では修正されています。おそらく浮動小数点まわりのバグかと。
-
(回避方法の例) 文字列charがeか+か判断する
char='e' *char='+' temp='1'char'5' if( temp = 1e+5 ) ; say 'char is e' ; endif if( temp = '1+5' ) ; say 'char is +' ; endif