IDL使用歴2年目の私がつまづいたポイントをまとめていく。
#1.キーワードの書き方
max関数を例にとって説明していく。
max関数は引数としてarrayを取り、arrayの要素の最大値を返す。キーワードとして名前付き引数"absolute"を指定すると、arrayの要素の絶対値の最大値を返す。
m = max(array, /absolute)
ここで出てきた/absolute
のように、キーワードに"/"をつけた表現は次のような表現と等価になる。
m = max(array, absolute = 1)
つまり/absolute
は「absoluteに1を渡す」という意味である。
IDLでは論理型のtrueとfalseの代わりに整数型の1と0が用いられるため、キーワードをセットすることを/absolute
のように1を代入することで表現している。
#2.論理型
先ほども述べたが、IDLでは1と0でtrueとfalseを表すため、真偽を判別する関数は1と0を返す。
例えばある変数が有限であるかを判別するfinite関数の場合には次のようになる。
> a = 1
> print, finite(a)
1
> b = !values.f_nan
> print, finite(b)
0
aは1という有限の値を持つので1が返ってくるが、bはNaNなので0が返ってくる。
ifやwhileの中の論理式も中身が1か0かで判別される。
if ~finite(a) then print, 'variable "a" is not finite.'
count = 0
while 1 do beign
count ++
print, count
if count eq 10 then break
endwhile
finiteについている"~"はnotを表すので、aが定義されていない場合には~finite(a) = 1
となる。従って上の式は「aが定義されていなければprint文を実行せよ」という意味になる。
下の文は「countが10になったらwhileを抜け出す」という文。
論理演算子を使うと1または0を出力する論理式を作ることができ、スカラーのみではなく配列にも適応できる。
IDL> a = 1
IDL> print, a le 0
0
IDL> print, a ge 0
1
IDL> b = [0, 1, 2, 3]
IDL> print, b ge 1
[0, 1, 1, 1]
#3.Where関数にまつわる注意点
おそらくIDLを使う上で最もよく使う関数であり、汎用性が非常に高い関数である。うまく使えばif文やfor文を使わないすっきりしたコードに仕上げることができる。
まず基本的な使い方を初めに説明していく。
IDL> arr = [4, 2, 0, 5, 6, 1]
IDL> idx = where(arr gt 3, count, complement = c, /null)
IDL> print, dummy
[0, 3, 4]
IDL> print, count
3
IDL> print, c
[1, 2, 5]
上の例では6個の要素を持つ一次元配列arrを定義し、arrの要素で3より大きな要素の"配列番号"をidxに代入している。ここで注意したいのがwhereは引数の論理型配列において要素が1である(条件を満たしている)位置を返すということだ。従って今回の例ではarr gt 3 = [1, 0, 0, 1, 1, 0]
という論理型配列の要素が1である位置をwhere関数で調べているということになる。論理型配列の要素が全て0の時には-1
というスカラーを返す。
初めての頃にやりがちなミスとして、要素が1か2である位置を調べたいと思った時に、
IDL> idx = where(arr eq [1, 2])
IDL> print, idx
1
としてしまうと、「idx = where( arr[0:1] eq [1, 2] )
」と同じ意味になってしまうので注意。複数の条件を組み込みたい場合には(arr eq 1) or (arr eq 2)
というようにor
を使って論理型配列を渡してやる必要がある。
次にキーワードについて説明していく。
count
:
戻り値の配列要素数を受け取る変数(名前は何でも良い)。少し特殊であるが、キーワードのように名前付きで渡す必要は無く、引数のように必須で渡すものではない。whereの戻り値によって条件分岐させたい時などに使うと良い。
例えば条件に一致する要素がない時に、何らかの命令を実行させるという場面で、
if where(arr eq 1) eq -1 then ...
のようにしてしまうと、whereの部分が配列として返ってきた場合(条件に一致する要素が見つかった場合)にはifの中の論理式が論理型スカラーではなく論理型配列になってしまって次のようなエラーメッセージが出てくる。
% Expression must be a scalar or 1 element array in this context: <BYTE Array[6]>.
% Execution halted at: $MAIN$
これを回避するためには、常にスカラーであるcount
を間に噛ませるか、isa
関数を用いたりして対処する。
idx = where(arr eq 1, count)
if count eq 0 then ...
if isa(idx, 'INT') then ...
この2つの表現はよく使うので覚えておくべき。n_elements
関数を用いても同じようなことができるが、条件を満たす要素がない場合にも-1というスカラーが返ってきてしまい、n_elements関数でも1が返ってきてしまうことに注意。
complement
:
このキーワードを指定すると、whereに渡された論理配列で要素が0(条件を満たさない)である位置(論理型配列にnotをつけて渡した時の戻り値と同じ)を受け取ることができるので、条件を満たす位置と満たさない位置を同時に知ることができる。
/null
:
デフォルトでは条件に一致した要素が見つからなかった時には-1というスカラーが返ってくると述べたが、/nullを指定すれば、-1の代わりに!NULL
を返すようにすることができる。この-1という戻り値が時々厄介であるので、/nullは使う機会が多いと思う。
IDLでは配列番号-1は配列の一番最後を表すので、次のような問題が起こってしまうことがある。
IDL> arr = [-1, -2, -3, -4, -5]
IDL> print, arr[ where(arr gt 0) ]
-5
arrの中から正の要素だけを表示しようとした時、arrの要素が全て負であるにもかかわらずarr[-1] = -5
が表示されてしまう。/nullを指定すればそのようなことを回避できる。
IDL> print, arr[ where(arr gt 0, /null) ]
!NULL
#4.ASCIIファイルの読み込み
ASCIIファイルの読み込みにはいくつか方法があるが、よく使うのはreadf
,read_ascii
あたりだろう。
readfとread_asciiの違いは、テンプレートファイルがあるかどうかである。readfで読み込む場合には、読み込みの時に、読み込みのフォーマットと読み込んだ値を受け取る変数を用意する必要がある。read_asciiでファイルを読み込むためには、何列目のデータをどのようなフォーマットでどんな名前の構造体要素に格納するのかを事前に指定するテンプレートファイルを用意しなければならないが、そのおかげでたった1行のコードで読み込みを行うことができる。
ここではreadfを使った基本的なファイルの読み込みの方法とその際の注意点を述べる。例として下のようなテキストファイル読み込みの例を示す。
1 1.0000 1.00000E+08 2000-01-01/00:00:00
2 10.0000 -1.00000E+09 2000-01-01/00:30:00
3 -12.0000 5.00000E+08 2000-01-01/01:00:00
pro read_txt
var1 = 0
var2 = 0.
var3 = 0.
var4 = ' '
openr, 1, './test.txt', /get_lun
while ~eof(lun)do begin
readf, lun, format = '(I2, 1x, F7.3, 1x, E12.5, 1x, A19)', $
var1, var2, var3, var4
print, var1, var2, var3, ' ', var4
endwhile
close, 1
end
ここで注意したい点は、初めに読み込んだ値を受け取る変数の型を宣言しているということだ。IDLでは変数の指定がない場合には、自動的にfloat型で読み込まれてしまうので、float型以外の値を読み込む場合には予め読み込む値の型を指定しなければならない。
* 初めの変数宣言をした場合
IDL> read_txt
1 1.00000 1.00000e+09 2000-01-01/00:00:00
2 10.0000 -1.00000e+09 2000-01-01/00:30:00
3 -12.0000 5.00000e+09 2000-01-01/01:00:00
* 初めの変数宣言をしなかった場合
IDL> read_txt
1.00000 1.00000 1.00000e+09 2000.00
2.00000 10.0000 -1.00000e+09 2000.00
3.00000 -12.0000 5.00000e+09 2000.00
このようにreadfで整数、文字列を読み込む際には注意が必要である。
##まとめ
以上が私がIDLを始めたての頃につまづいたポイントをまとめたものだ。
L3HARRIS社のホームページ(https://www.harrisgeospatial.com/docs/using_idl_home.html)に各関数・プロシージャの使い方が詳細に書いてあるので、困った時にはそこを見てもらえれば基本的には大抵の問題は解決するはず。あとIDLは日本語のリソースよりも英語のリソースの方が遥かに充実しているので、英語で検索をかけるとあっさり解決することも多い。