IDL(Interactive Data Language)で初心者が気をつけるべきポイント


IDL使用歴２年目の私がつまづいたポイントをまとめていく。

#1.キーワードの書き方
max関数を例にとって説明していく。
max関数は引数としてarrayを取り、arrayの要素の最大値を返す。キーワードとして名前付き引数"absolute"を指定すると、arrayの要素の絶対値の最大値を返す。

```idlang
m = max(array, /absolute)
```
ここで出てきた`/absolute`のように、キーワードに"/"をつけた表現は次のような表現と等価になる。

```idlang
m = max(array, absolute = 1)
```

つまり`/absolute`は「**absoluteに１を渡す**」という意味である。
IDLでは論理型のtrueとfalseの代わりに整数型の1と0が用いられるため、キーワードをセットすることを`/absolute`のように１を代入することで表現している。




#2.論理型
先ほども述べたが、IDLでは１と０でtrueとfalseを表すため、真偽を判別する関数は１と０を返す。
例えばある変数が有限であるかを判別するfinite関数の場合には次のようになる。

```idlang
> a = 1
> print, finite(a) 
   1
> b = !values.f_nan
> print, finite(b)
   0
```
aは1という有限の値を持つので1が返ってくるが、bはNaNなので０が返ってくる。
ifやwhileの中の論理式も中身が１か０かで判別される。


```idlang
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が１０になったらwhileを抜け出す」という文。

論理演算子を使うと１または０を出力する論理式を作ることができ、スカラーのみではなく配列にも適応できる。

```idlang
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文を使わないすっきりしたコードに仕上げることができる。

まず基本的な使い方を初めに説明していく。

```idlang
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]
```

上の例では６個の要素を持つ一次元配列arrを定義し、arrの要素で３より大きな要素の"配列番号"をidxに代入している。ここで注意したいのがwhereは引数の論理型配列において要素が１である（条件を満たしている）位置を返すということだ。従って今回の例では`arr gt 3 = [1, 0, 0, 1, 1, 0]`という論理型配列の要素が１である位置をwhere関数で調べているということになる。論理型配列の要素が全て０の時には`-1`というスカラーを返す。

初めての頃にやりがちなミスとして、要素が1か２である位置を調べたいと思った時に、

```idlang
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の戻り値によって条件分岐させたい時などに使うと良い。

例えば条件に一致する要素がない時に、何らかの命令を実行させるという場面で、

```idlang
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`関数を用いたりして対処する。

```idlang
idx = where(arr eq 1, count)
if count eq 0 then ...
if isa(idx, 'INT') then ...
```
この２つの表現はよく使うので覚えておくべき。`n_elements`関数を用いても同じようなことができるが、条件を満たす要素がない場合にも-1というスカラーが返ってきてしまい、n_elements関数でも１が返ってきてしまうことに注意。



`complement`:
このキーワードを指定すると、whereに渡された論理配列で要素が０（条件を満たさない）である位置（論理型配列にnotをつけて渡した時の戻り値と同じ）を受け取ることができるので、条件を満たす位置と満たさない位置を同時に知ることができる。


`/null`:
デフォルトでは条件に一致した要素が見つからなかった時には-1というスカラーが返ってくると述べたが、/nullを指定すれば、-1の代わりに`!NULL`を返すようにすることができる。この-1という戻り値が時々厄介であるので、/nullは使う機会が多いと思う。
IDLでは配列番号-1は配列の一番最後を表すので、次のような問題が起こってしまうことがある。

```idlang
IDL> arr = [-1, -2, -3, -4, -5]
IDL> print, arr[ where(arr gt 0) ]
       -5 
```
arrの中から正の要素だけを表示しようとした時、arrの要素が全て負であるにもかかわらず`arr[-1] = -5`が表示されてしまう。/nullを指定すればそのようなことを回避できる。

```idlang
IDL> print, arr[ where(arr gt 0, /null) ]
      !NULL
```


#4.ASCIIファイルの読み込み
ASCIIファイルの読み込みにはいくつか方法があるが、よく使うのは`readf`,`read_ascii`あたりだろう。
readfとread_asciiの違いは、テンプレートファイルがあるかどうかである。readfで読み込む場合には、読み込みの時に、読み込みのフォーマットと読み込んだ値を受け取る変数を用意する必要がある。read_asciiでファイルを読み込むためには、何列目のデータをどのようなフォーマットでどんな名前の構造体要素に格納するのかを事前に指定するテンプレートファイルを用意しなければならないが、そのおかげでたった１行のコードで読み込みを行うことができる。
　ここではreadfを使った基本的なファイルの読み込みの方法とその際の注意点を述べる。例として下のようなテキストファイル読み込みの例を示す。

```test.txt
 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
```

```idlang:read_txt.pro
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](https://www.harrisgeospatial.com/docs/using_idl_home.html ))に各関数・プロシージャの使い方が詳細に書いてあるので、困った時にはそこを見てもらえれば基本的には大抵の問題は解決するはず。あとIDLは日本語のリソースよりも英語のリソースの方が遥かに充実しているので、英語で検索をかけるとあっさり解決することも多い。