Spedas idlref - spedas-j/member_contrib GitHub Wiki
以下はH22年度STE研究集会「多点衛星・地上データ解析による磁気圏ダイナミクス研究会 」@高知高専で配布されたIDLリファレンスリストを作者(井口さん@宇宙研、高田さん@高知高専)の許可を得て転載させて頂いたものです。
このリファレンス・リストは、IDLでプログラムを書いたことのある人向けに書かれています。IDLは非常に冗長性の高いプログラムですので、個々のプログラマーによってサブルーチン類の使い方が異なります。以下では、TDASを有効に使うために必要ないくつかのIDLの概念・サブルーチンについて、説明しました。
- 配列
- WHERE関数
- 構造体
- NaN
- N_ELEMENTS関数
- KEYWORD_SET関数
- string処理
- FILE_SEARCH関数
- procedureとfunctionの違い
IDLにおいて簡潔なプログラムを作成するために重要なことは配列を自由自在に使いこなすことです。IDLの配列はFortranとは異なり、どの段階でも配列を作成でき、配列の要素数を容易に変えることができます。行列の乗算も演算子(#)を用いて簡単に記述できます。また、IDLでは、配列を用いたベクトル演算の処理が速いです。
(例1) 要素数10の整数型配列Xを作成
IDL> X=INTARR(10)
IDL> print,X
(実行結果)
0 0 0 0 0 0 0 0 0 0
(例2) 配列の要素指定と代入
IDL> p=5
IDL> X=INDGEN(10)
IDL> D=X[p-1:p+1]
IDL> print,D
(実行結果)
4 5 6
DにX[4]、X[5]、X[6]が代入されるとDは3要素の配列になります。
(例3) 添え字配列の使い方 WHERE関数と組み合わせて使うと便利です。
IDL> E=[6, 5, 1, 8, 4, 3]
IDL> F=[0, 2, 4, 1]
IDL> G=E[F]
IDL> print,G
(実行結果)
6 1 4 5
Fは添え字配列として扱っています。添え字(要素番号)0, 2, 4, 1に対応する配列Eの値がGに代入されます。Gは4要素の配列になります。
多次元配列は1次元配列と同じように使えますが、添え字の順番に注意する必要があります。2次元配列は数学でAijと表記されます。しかし、IDLではA[j, i]と表記しなければなりません。1度、自分で確認してみることをお勧めします。3次元以上の配列についても添え字は転置された表記方法が使われています。
WHERE関数は配列の中から指定した条件に合う要素の要素番号だけを抜き取り、要素番号の配列(添え字配列)を返します。例えば、配列の中から特定の値をもつ要素を調べることができます。また、ある期間のデータから任意の期間のデータを抜き出すとき等に使うとプログラムが簡潔になり、非常に便利です。
(例1) WHERE関数の使い方
0の2乗から9の2乗が順番に格納された配列Sを用意します。
IDL> S = INDGEN(10)
IDL> S=S*S
IDL> PRINT, S
(実行結果)
0 1 4 9 16 25 36 49 64 81
WHRER関数を使ってSのうち、値が30以上の要素の要素番号がTに代入されます。
IDL> T = WHERE(S GT 30)
IDL> print, T
(実行結果)
6 7 8 9
添え字配列Tを使って、Tの値(Sのうち、値が30以上の要素の要素番号)が代入された新しい配列S2を作成します。
IDL> S2 = S(T)
IDL> print, S2
(実行結果)
36 49 64 81
Sのうち、30以上の値を持つ要素が何個あるかを調べるには、S GT 30のあとに変数(ここではcount)を記述します。
IDL> T = WHERE(S GT 30, count)
IDL> print, count
(実行結果)
4
COMPLEMENT=変数(ここではS_complement)を記述するとTに代入された要素番号以外(Sのうち、値が30より小さい要素の要素番号)の添え字配列が作成され、変数に代入されます。
IDL> T = WHERE(S GT 30, count, COMPLEMENT=S_complement)
IDL> print, S_complement
(実行結果)
0 1 2 3 4 5
NCOMPLEMENT=変数(ここではcount_c)を記述するとTに代入された要素番号以外(Sのうち、値が30より小さい要素の要素番号)の添え字配列の総要素数が変数に代入されます。
IDL> T = WHERE(S GT 30, count, COMPLEMENT=S_complement, NCOMPLEMENT=count_c)
IDL> print, count_c
(実行結果)
6
(例2) 配列と変数、配列と配列の比較
IDL> U = [1, 4, 1, 8, 6, 7, 2, 4, 8, 4]
IDL> V = 4
IDL> print, WHERE(U EQ V)
(実行結果)
1 7 9
IDL> W = [0, 4, 1]
IDL> print, WHERE(U EQ W)
(実行結果)
1 2
WHERE(U EQ V)で配列Uの要素と変数Vの値が等しい要素番号を抜き出し、添え字配列を作成できます。配列と変数の場合、変数と配列の各要素が比較されます。
WHERE(U EQ W)で配列Uの要素と配列Wの要素が等しい要素番号を抜き出し、添え字配列を作成できます。配列と配列の場合、同じ添え字番号同士を比較するため、小さな配列(W)の最大添え字番号までしか実行されないことに注意しなければなりません。
構造体も配列と同様にわかりやすいプログラムを作成するために必要不可欠なものです。ここではIDLで構造体を作成する方法を説明します。構造体には名前付き構造体と名前なし構造体があります。
(例1) 名前付き構造体の定義の仕方
IDL> H={ CAR, NAME : ’ ’ , COLOR : ‘ ’, MODEL : 0 }
IDL> help, /st
(実行結果)
** Structure CAR, 3 tags, length=28, data length=26:
NAME STRING
COLOR STRING
MODEL INT
名前付き構造体は以下の方法で定義します。
構造体変数名={ 構造体名, メンバ名1 : メンバ定義1, メンバ名2 : メンバ定義2 }
構造体の定義はCREATE_STRUCT関数でも可能です。また、tdasにはSTR_ELEMENTというプロシージャがあり、構造体のメンバ名等を自由に変更することができます。
構造体はhelpプロシージャを使って構造体の一覧を見ることができます。help,構造体変数名,/structureと記述することで、配列のメンバ名とその型が表示されます。名前付き構造体はhelp,/structureでも確認できます。キーワードは省略形の/stとしても構いません。キーワード名は全て打ちこまなくてもIDLが自動で先頭文字から検索し実行します。ただし、helpプロシージャにはSHARED_MEMORY、SOURCE_FILES、SYSTEM_VARIABLESというキーワードもあるため、/sと省略してもstructureキーワードは自動的に実行されません。
(例2) 構造体の使い方(例1を実行した後に入力してください。)
IDL> H.NAME=’PRIUS’
IDL> H.COLOR=’BLACK’
IDL> H.MODEL=2003
IDL> print, H.NAME, H.COLOR, H.MODEL
(実行結果)
PRIUS BLACK 2003
IDL> J=H
IDL> print, J
(実行結果)
{ PRIUS BLACK 2003}
値は 構造体変数名.メンバ名 (構造体名+ピリオド+メンバ名)とすると代入できます。構造体変数HをJに代入すると構造体のコピーがJに作成されます。したがって、Jも同じCAR構造体になり、同じ値をもちます。構造体変数名が異なるためメンバが共有されているわけではありません。
(例3) 構造体の引き渡し(例2を実行した後に入力してください。)
IDL> read, H.NAME
(実行結果)
PRIUS
IDL> K=H.NAME
IDL> read, K
プロンプトが「IDL>」から「:」に変わるので、好きな文字をキーボードから入力してください。
ここでは「MARCH」と入力した例を示します。入力するとログ表示ウィンドウに「: MARCH」と表示されます。
IDL> H.NAME=K
IDL> print, H.NAME
(実行結果)
MARCH
構造体のメンバを引数として扱う場合について説明します。
まず、プロシージャや関数の引数として変数を用いる場合について復習します。呼び出されたサブプロシージャで変数の中身を書き換えます。するとメインプロシージャに戻った後でも変更が反映されます。これは引数が参照渡しだからです。
次に引数が構造体変数の場合について説明します。構造体変数が引数の場合は変数と全く同様です。サブプロシージャで構造体のメンバの値を変更したら、メインプロシージャに戻った後でも変更が反映されています。
最後に引数が構造体のメンバ(H.NAME等)の場合について説明します。構造体のメンバが引数の場合、サブプロシージャで構造体のメンバを変更しても、メインプロシージャには反映されません。これは引数が値渡しだからです。サブプロシージャ名, H.NAMEと書いてあっても、サブプロシージャ名, ‘PRIUS’と書いてあるのと同じことです。このように書くとサブプロシージャで変更してもメインプロシージャで反映されない理由が良く分かると思います。
ここではreadプロシージャがサブプロシージャになります。readプロシージャはプロンプトに入力された文字を変数に代入することができます。しかし、上記のように構造体のメンバは値で引き渡されるため、最初の実行結果ではログ表示ウィンドウにPRIUSと表示されるだけです。
構造体のフィールドを変更したい場合は、まず、型と属性を新しい変数(K)にコピーします。次にコピーした変数を使ってreadプロシージャを実行します。最後にコピーした変数を構造体のフィールドに代入します。
(例4) 構造体配列(例3を実行した後に入力してください。)
IDL> CAR_CATALOG=REPLICATE({CAR},100)
IDL> CAR_CATALOG.NAME=’EMPTY’
IDL> print, CAR_CATALOG.NAME
(実行結果)
EMPTY EMPTY EMPTY EMPTY ・・・・・・・・・・EMPTY EMPTY EMPTY EMPTY
IDL> CAR_CATALOG(0)={CAR, ‘FREED’, ‘LUMINOUS_BLUE’, 2008}
IDL> print, CAR_CATALOG(0)
(実行結果)
{ FREED LUMINOUS_BLUE 2008}
IDL> L= CAR_CATALOG.NAME
IDL> print, L
(実行結果)
EMPTY EMPTY EMPTY EMPTY ・・・・・・・・・・EMPTY EMPTY EMPTY EMPTY
REPLICATE関数は指定された要素数の配列を作成します。ここでは、100個のCAR構造体を持つ構造体配列CAR_CATALOGが作成されます。要素番号を指定せずに代入した場合は。全ての要素に同じ値が代入されます。値の代入は基本的に例1)や例2)とほぼ同じで、異なるのは要素番号を付け加えるていることだけです。要素指定せずにCAR_CATALOG.NAMEを新しい変数(L)に代入すると、新しい変数はCAR_CATALOG.NAMEと同じ値を持つ100個の1次元配列になります。
NaNはNot a Numberを意味します。NaNは!VALUES構造体に代入されている値です。!VALUES構造体は以下のように4つのフィールドを持ち、NaNは F_NANとD_NANに格納されています。
F_INFINITY FLOAT Infinity
F_NAN FLOAT NaN
D_INFINITY DOUBLE Infinity
D_NAN DOUBLE NaN
例えば、対数LOG10-5はNaNを返します。IDLでは計算できない命令に対してNaNが返されることがあります。また、データがない場合もNaNが代入されることがあります。THEMISの観測データを扱うときは後者でよく出会うでしょう。
(例1)
IDL> M=ALOG10(-5)
IDL> print, M
(実行結果)
IDL> -NaN
(例2) 配列にNaNがあるかどうかチェックする方法
IDL> N = FLTARR(10)
IDL> N[0:2]=FINDGEN(3)
IDL> N[3] = !VALUES.F_NAN
IDL> N[4] = -!VALUES.F_NAN
IDL> N[5] = 0
IDL> N[6] = !VALUES.F_INFINITY
IDL> N[7] = -!VALUES.F_INFINITY
IDL> N[8:9]=FINDGEN(2)
IDL> print, N
(実行結果)
0.000000 1.00000 2.00000 NaN -NaN 0.000000 Inf -Inf 0.000000 1.00000
IDL> print, FINITE(N, /NAN)
(実行結果)
0 0 0 1 1 0 0 0 0 0
IDL> print, WHERE(FINITE(N, /NAN))
(実行結果)
3 4
IDL> print, WHERE(FINITE(N, /NAN, SIGN=1))
(実行結果)
3
配列N[3]に+NaN、N[4]に-NaNを代入します。配列Nを表示するとNaN、-NaNと表示されている事がわかります。
配列Nをplotプロシージャで描画すると、横軸が要素番号、縦軸が値になります。このとき、NaNはMissing dataとして扱われ、プロットされず、線で結ばれません。またInfinityもプロットされません。
配列内にNaNがあるかどうか調べるにはFINITE関数とWHERE関数を使うと便利です。FINITE関数はNaNがあると1を返します。FINITE関数内で配列を指定すると要素ごとにチェックされ、その結果が配列で返されます。NaNがあるかどうか調べる場合は/NANキーワードが必要です。必要に応じてSIGNで正負を指定できます。FINITE関数をWHERE関数内で使用すると配列Nの中にあるNaNの要素番号を1行で出力できます。
N_ELEMENTSは非常に簡潔な関数で、配列や変数の総要素数を返します。
(例1) N_ELEMENTS関数の使い方
IDL> Q=INTARR(25)
IDL> print, N_ELEMENTS(Q)
(実行結果)
25
IDL> R = INTARR(4, 5, 3, 6)
IDL> print, N_ELEMENTS(R)
(実行結果)
360
IDL> print, N_ELEMENTS(R[*, 0, 0, 0])
(実行結果)
4
2次元以上の配列の場合、配列名だけ入力すると総要素数が返されます。要素番号で範囲指定を行えばその分の総要素数が返されます。
キーワードはIDLが持つ強力な武器の一つです。KEYWORD_SETはキーワードが付加されていた場合にTRUE(1)を返し、そうでない場合はFALSE(0)を返します。同じプロシージャや関数を使用する場合でもパラメータ等を変えたいことがあります。そのようなときに使うと便利です。
(例1) KEYWORD_SETの使い方
以下のプログラムをproc_keyowrd_test_sub.proという名前で保存し、コンパイルします。
--------------------------------------------------------------------------------------
pro proc_keyowrd_test_sub, B=B, E=E
if keyword_set(B) then print, 'PLOT B'
if keyword_set(E) then print, 'PLOT E'
return
end
---------------------------------------------------------------------------------------
次に以下のプログラムをproc_keyowrd_test_main.proという名前で保存し、コンパイル・実行します。
---------------------------------------------------------------------------------------
pro proc_keyword_test_main
proc_keyowrd_test_sub, /B
end
---------------------------------------------------------------------------------------
IDL> proc_keyword_test_main
(実行結果)
PLOT B
proc_keyowrd_test_sub はサブプロシージャで、BとEというキーワードを備えています。
proc_keyowrd_test_mainはメインプロシージャで、サブプロシージャを呼び出すときにキーワードを付加することができます。ここではサブプロシージャを呼び出すと以下のような処理を行います。
Bが付加された場合…PLOT Bと表示 Eが付加された場合…PLOT Eと表示 何も付加されていない場合…何も表示しない
実際にメインプロシージャにキーワードをつけてコンパイル、実行を行い、KEYWORD_SETの動作を確認してみてください。
(例1) 演算子(+)で文字を連結
IDL> a='Life is like rid'
IDL> b='ing a bicycle.'
IDL> c='you must keep moving.'
IDL> d='To keep your balance'
IDL> e=a+b+' '+d+' '+c
IDL> print,e
(実行結果)
Life is like riding a bicycle. To keep your balance you must keep moving.
(例2) STRPOS、STRMID、STRUPCASE、STRLOWCASE関数の使い方
IDL> print, STRPOS('IDL is fun', 'fun')
(実行結果)
7
IDL> print, STRMID('IDL is fun', 4, 2)
(実行結果)
is
IDL> print, STRUPCASE('IDL is fun')
(実行結果)
IDL IS FUN
IDL> print, STRLOWCASE('IDL is fun')
(実行結果)
idl is fun
STRPOS関数…目的の文字列('IDL is fun')から指定した文字列('fun')を探し、何文字目から始まるかを検索します。
STRMID関数…目的の文字列('IDL is fun')から指定した位置(4)をはじめとして指定した文字数分(2)を抜き出します。
STRUPCASE…目的の文字列を全て大文字にします。
STRLOWCASE…目的の文字列を全て小文字にします。
(例3) FORMATの使い方
IDL> str=STRARR(4)
IDL> str[0]='water'
IDL> str[1]='juice'
IDL> str[2]='beer'
IDL> str[3]='wine'
IDL> print,str
(実行結果)
water juice beer wine
IDL> print, FORMAT='("<",a5,">")', str
(実行結果)
<water>
<juice>
< beer>
< wine>
IDL> print, FORMAT='(2("<",a5,">"))', str
(実行結果)
<water><juice>
< beer>< wine>
print,FORMAT=’(フォーマット形式)’,文字列 で文字の表記方法を変更する。何もせずにprintを実行すると半角スペースで区切られた表記になります。フォーマット中で”(ダブルクォーテーション)で囲まれた文字がそのまま出力されます。文字を出力する場合はa数字と記述します。aは文字を出力することを意味し、その後の数字は文字数を指定します。
数字(…) と書くとカッコ内のフォーマットを数字の回数分だけ繰り返すことができます。
FILE_SEARCHは指定した条件に合うファイルを検索し、ファイル名を文字列配列に格納します。
(例1) FILE_SEARCH関数の使い方
カレントディレクトリのフォルダ名とファイル名を全てfile_stringに代入します。
IDL> file_string = FILE_SEARCH()
IDL> print, FORMAT='(a100)', file_string
カレントディレクトリから全ての.proファイルをfile_stringに代入します。*はワイルドカードです。
IDL> file_string = FILE_SEARCH('*.pro')
IDL> print, FORMAT='(a100)', file_string
カレントディレクトリ内の全ての.proファイル数を出力します。
IDL> print, N_ELEMENTS(FILE_SEARCH('*.pro'))
フロッピーディスクドライブを除く全てのドライブの最上位フォルダ名とファイル名をfile_stringに代入します。
IDL> file_string =FILE_SEARCH('[!ab]:*')
IDL> print, FORMAT='(a100)', file_string
カレントディレクトリ内のaからdで始まる全てのフォルダ名とファイル名をfile_stringに代入します。
IDL> file_string = FILE_SEARCH('~/[a-d]*', /EXPAND_TILDE, /FOLD_CASE)
IDL> print, FORMAT='(a100)', file_string
カレントディレクトリ内のaからdで始まる全てのフォルダ名をfile_stringに代入します。
IDL> file_string = FILE_SEARCH('~/[a-d]*', /EXPAND_TILDE, /FOLD_CASE, /TEST_DIRECTORY)
IDL> print, FORMAT='(a100)', file_string
/EXPAND_TILDE
(チルダ)はホームディレクトリを指します。ホームディレクトリはメニューのFileからPreferences→Startup→Working Directoryで確認できます。探したい場所に’/’と書くとホームディレクトリ以下のファイルやフォルダを検索します。ただし、/EXPAND_TILDEキーワードをつけなければ、がホームディレクトリである事を認識しません。したがって、file_string = FILE_SEARCH('/[a-d]*', /FOLD_CASE) では機能しません。
/FOLD_CASE
このキーワードは検索するファイルやフォルダ名の大文字、小文字の区別を行わない場合に用います。たとえば、test.txtとtest.TXTというファイルが同一ディレクトリに存在する場合を考えます。このキーワードをつけない場合、以下のように小文字のファイルしか検索されません。
IDL> file_string=file_search('~/*.txt',/expand_tilde)
IDL> print,file_string
/home/ユーザー名/test.txt
しかし、/FOLD_CASEをつければ以下のように2つとも検出されます。
IDL> file_string=file_search('~/*.txt',/expand_tilde,/fold_case)
IDL> print,file_string
/home/ユーザー名/test.TXT /home/ユーザー名/test.txt
なお、Windows機は同一ディレクトリにtest.txtとtest.TXTのようなファイルを保存できないため、ほとんど使用することはありません。
/TEST_DIRECTORY
検索範囲のうち、ディレクトリのみを検索します。
プロシージャは固有の名前を持ったプログラム単位であり、他のプログラム単位から呼び出され、特定の処理を実行します。呼び出し側のプログラム単位とプロシージャは、引数によりデータの受け渡しを行います。
(例1) プロシージャの作り方
pro proc_main, para, key=key
(ここに実行文を記述します)
end
プロシージャは「pro」で始まり「end」で終わります。proのあとに1つ以上の半角スペースをつけてプロシージャ名(ここではproc_main)を記述します。その後に、引数(ここではpara)、キーワード(ここではkey=key)を記述します。改行後、実行文を記述します。pro~と記述した行に実行文は書けません。
引数やキーワードが多くなる場合は適宜、行末に「$」をつけて改行するとよいでしょう。エディタ中で行末に「$」があれば次の行も含めて1つの命令としてコンパイルされます。例えば以下のように記述します。もちろん、「$」は実行文でも使用可能です。
----------------------------------------------------------------------------------------
pro_プロシージャ名, 引数1, 引数2, 引数3, 引数4, $
キーワード1=キーワード1, $
キーワード2=キーワード2, $
キーワード3=キーワード3
(実行文)
end
実行文中で他のプロシージャを呼び出す場合は以下のように記述します。キーワードには/をつけてください。
プロシージャ名, 引数, /キーワード
(例2) プロシージャの例
pro print_test
print,’Hello!’
end
関数はプロシージャと同様のプログラム単位です。関数自体が値を呼び出し側に戻すので、式の中で利用できる点がプロシージャと異なります。
(例3) 関数の作り方
function func_test, para, key=key
(ここに実行文を記述します)
return, 戻り値
end
関数は「function」で始まり「end」で終わります。関数には戻り値があり、「return」が「end」の前に必要です。functionのあとに1つ以上の半角スペースをつけて関数名(ここではfunc_test)を記述します。その後に、引数(ここではpara)、キーワード(ここではkey=key)を記述します。改行後、実行文を記述します。function~と記述した行に実行文は書けません。
(例4) 関数の例
以下のプログラムをfunc_power.proという名前で保存し、コンパイルします。
------------------------------------------------------------------------------
function func_power, b, cube=cube
c=b
b=b*b
if keyword_set(cube) then b=b*c
return, b
end
-------------------------------------------------------------------------------
次に以下のプログラムをfunc_test_main.proという名前で保存し、コンパイルします。
-------------------------------------------------------------------------------
pro func_test_main
a=10
a=func_power(a, /cube)
print, a
end
--------------------------------------------------------------------------------
IDL> func_test_main
(実行結果)
1000
関数を呼び出すときは以下のように記述します。
関数名(引数, /キーワード)
上のプログラムではcubeキーワードを付加することで3乗を計算し、キーワードがない場合は2乗を計算します。
1996, Research System, Inc., IDL User’s Guide(日本語版)