Fortranでcsvファイルを開いて1行ずつ読み込む
みなさんこんにちは。おこめまんです。
今回はFortranで処理したいファイルを開いて、読み込む方法をご紹介します。
はじめに
気象屋は多くの場合Fortranを使って気象データの処理を行います。
しかし、Fortran初心者の場合、どうやってファイルの中身を読み込んで処理するんだろうと疑問に思うかと思います。
私もはじめはFortranの仕組みがわからず、ファイルの開き方、データの読み込み方など理解に苦しみました。
そこで、今回は「ダウンロードしたアメダス10分間値のデータをFortranで開いて読み込み、中身を画面に表示する方法」をご紹介したいと思います。
読み込むデータファイルとその中身
今回は、以前スクレイピングでゲットした大間アメダスのデータを書き込んだファイルをFortranで開き、読み込んでみます。
<ファイル名>
amd10_31001_201801.csv
<ファイルの中身>
はじめの数行を以下にお見せします。
各列はそれぞれ、
「年」「月」「日」「時」「分」「秒」「降水量」「気温」「平均風速」「風向(平均風速)」「最大瞬間風速」「風向(最大瞬間風速)」「日照時間」
となっています。
よって、最初の1行目には
2018年1月1日0時10分0秒の降水量、気温、平均風速、風向(平均風速)、最大瞬間風速、風向(最大瞬間風速)、日照時間が書かれています。
このデータをFortranで読み込んで、画面に表示できるようにしましょう。
使用した言語
Fortran95
Fortranプログラム
以下を書き込んだ「open_amedas_data.f95」というプログラムを作成します。
program open_amedas_data
implicit none
integer :: year, month, day, hour, minute, second
real :: prc, temp, ws, wd, gws, gwd, sun
character :: ifile*100
ifile="amd10_31001_201801.csv"
open(30, file=trim(ifile), status='old')
do
read (30, *, end = 99, err=98) year, month, day, hour, minute, second, prc, temp, ws, wd, gws, gwd, sun
write (6,*) year, month, day, hour, minute, second, prc, temp, ws, wd, gws, gwd, sun
end do
99 write (6, *) "Finish"
98 write (6, *) "ERROR"
close (30)
stop
end program open_amedas_data
プログラムの解説
program open_amedas_data
⇒ Fortranプログラムの名前を書きます。今回は「open_amedas_data.f95」というプログラムを作成したので、「open_amedas_data」となります。
-----------------------------------------------------------------
implicit none
integer :: year, month, day, hour, minute, second
real :: prc, temp, ws, wd, gws, gwd, sun
character :: ifile*100
⇒ A~G列は年、月、日、時、分、秒となっていますので、それぞれyear, month, day, hour, minute, secondとして変数指定を行います。integerとしているのは、A~G列は整数値であるためです。
⇒ H~M列は、気温、平均風速、風向(平均風速)、最大瞬間風速、風向(最大瞬間風速)、日照時間です。これらは実数ですので、realとしてそれぞれ変数指定を行います。
⇒ 開くファイルである「amd10_31001_201801.csv」をifileとしたいためここで変数指定を行います。characterとしているのは、ファイル名を文字列として処理するためです。31001は数字だからintegerなのではと思うかもしれませんが、ファイル名は文字列である必要があります。またifile*100の100という数字ですが、これはifileの文字数が100であるという意味です。今回開くファイルは100文字ではありませんが、多くしていてもこの時点では問題ありません。※open文である処理をする必要があります。
-----------------------------------------------------------------
ifile="amd10_31001_201801.csv"
open(30, file=trim(ifile1), status='old')
⇒ ifile="〇〇"で開くファイルを指定します。
open文でファイルを開きます。30は装置番号で、任意の数字にすることができます。装置番は1~99の間で任意に指定することができますが、5は標準入力(キーボード)、6は
標準出力(画面)となっているため、これらの数字は利用しないようにしましょう。
trimは先ほど、ifile*100として文字列を多くとっていたファイル名の空白をカットしてくれるものです。実際「amd10_31001_201801.csv」は22文字ですから余分な78文字分の空白を切り取ります。trimを書かずそのままfile=ifileとしてしまうとうまく開くことができません。
status='old'は「amd10_31001_201801.csv」はもともと存在するファイルだと宣言するものです。よく利用するのはold、replaceです。詳しい説明は割愛します。
これで、ファイルを開くことができました。
-----------------------------------------------------------------
do
read (30, *, end = 99, err=98) year, month, day, hour, minute, second, prc, temp, ws, wd, gws, gwd, sun
write (6,*) year, month, day, hour, minute, second, prc, temp, ws, wd, gws, gwd, sun
end do
⇒ doループすることで1行ずつファイルの中身を読み込みます。ファイルの読み込みはreadです。装置番号は先ほどopenの際に使用した数字にします。またendで中身を読みこみ、最終行に達した場合に99にジャンプします。errで読み込みの際にエラーがあった場合98にジャンプします。
<注意>read文で読み込む際、列の数と変数の数が同じになっているか確かめましょう(year, month, day, hour, minute, second, prc, temp, ws, wd, gws, gwd, sun)。今回開いたcsvファイルは13列であるため、変数も13個です。
writeで先ほど読み込んだ中身を1行ずつ画面に表示させます。装置番号の6は画面表示でしたね。
-----------------------------------------------------------------
99 write (6, *) "Finish"
98 write (6, *) "ERROR"
⇒ 先ほどのend、errのジャンプ先です。endの場合には画面に「Finish」、errの場合には画面に「ERROR」と表示されます。
-----------------------------------------------------------------
close (30)
⇒ 開いていたファイルを閉じます。
-----------------------------------------------------------------
stop
⇒ プログラムをstopさせます。書かなくても今回はOKです。
-----------------------------------------------------------------
end program open_amedas_data
⇒ プログラムの終了を宣言します。
なんとなく理解できたでしょうか。doループのかけ方やデータ型、装置番号など細かい説明は他のサイトを参照してください。
プログラムの実行
さて、先ほどのプログラム「open_amedas_data.f95」を実行してみましょう。
f95 open_amedas_data.f95
./a.out
この2行をコマンドラインで打ってみましょう。
おそらく画面下から上にものすごい勢いで数字が流れているのではないでしょうか。
成功です!
最後に
今回、csvファイルを扱いましたが、txtファイルでも同様に開くことができます(ただし、カンマで区切ったデータである必要があります)。
これで、データ処理の第1歩「ファイルをFortranで開く」ことができました。データ解析の際はファイルをFortranで開き様々な処理を行うことがほとんどです。自由自在にデータを扱えるようにしたいですね。
それではまた次回。おこめまんでした。