Showing posts with label Fortran. Show all posts
Showing posts with label Fortran. Show all posts

2015-01-18

Fortran でのバイナリ (unformatted, binary) の扱いについてのメモ

前提

FIELDVIEW で Plot3D の binary 読み込む というのを昨日書いた。だけど、Plot3D だけじゃなくて、ファイルサイズ削減のため Fortran でバイナリ形式で読み書きしたい。ただそもそも unformatted まわりがよくわからん…。たとえば form="unformatted" と form="binary" はどう違うのか?あまり変わらないという話もある(参考1, 参考2)けど、じゃあ多少は違うのだろうか?とか。

そこで、ググって調べつつテストコード書いてバイナリエディタで中身開いて確認してみた。結果、ちょっとずつわかってきた。今のところの理解をメモしておく。

なお character についてはとりあえず考えていない。 integer, real(4), real(8) のみ。バイトオーダーも気にしてない。

比較

まずバイナリ形式を扱うための open にはいくつかの形式がある。恐らく次の4種類?
  • open( ..., form="unformatted", access="sequential")
  • open( ..., form="unformatted", access="direct", recl=数字) ← position 指定不可。 ifort での場合コンパイル時は "-assume byterecl" を付けるべし
  • open( ..., form="unformatted", access="stream") ← Fortran 2003 以降(gfortran, g95, ifort 全部大丈夫そう。よほど古くなければ)
  • open( ..., form="binary") ← ifort 独自仕様で stream と同義
一番基本的なのが sequential のようだが、これだと一行というか ( a(i), i=1,10 ) みたいな塊の前後にヘッダとフッタが自動的に挿入される。したがって縦に長いというか do i=1,1000000 みたいに改行しまくるとヘッダとフッタ分でサイズが増える。

direct はそういうことはないが、読み書き位置を read(m_num, rec=i) みたいに一々指定しないといけないようで、小さいデータならいいが複雑になるとミスりそうでちょっと怖い。あと
positon="append" を付けるとコンパイルの時点で怒られる。どうやら、 position="append" は direct や stream だとできなそう。それから、integer, single precision, double precision が混在するときは、一番大きな double precision に合わせて record という固定長の領域(?よくわかってないがそんなイメージ)を確保しないといけないっぽい。そうすると integer, single precision の部分はデータは半分だけで残りは0でフィルされてだいぶ無駄になってるみたいだ。

stream は新しいやり方…というか C/C++ に合わせたい( の stream?)とかのモチベーションで新しく出てきたやつらしい。固定長の record base じゃないので変数の型に合わせて必要なサイズずつ入っていく。型が混在する場合はファイルサイズの節約になる。また、読むときは read(m_num, posipos=i) みたいに指定するようで、direct ほどでなくとも頭は使いそうだが、書き出しの際は rec= なんてのはないので、direct よりも楽。なお http://www.star.le.ac.uk/~cgp/streamIO.html によると formatted でも使えるとのこと。

結論

というわけで、なるべく横長にして sequential を使うか、stream かのいずれかにしようと思う。

参考リンク

一部は本文中と重複してる。

テストに使ったコード

https://docs.google.com/document/d/1m9iOSI26PJcyJEZuVSuMiwTc0miMOMwMwp5prEAqFjc/edit?usp=sharing
(google docs が開くのでコピペして保存したら使えると思う)


UPDATE 2015-01-19

実際に actionaccess="sequential" にして、横に長く write(iunit) ( a(i), i=1,4800000 ) みたいにしたやつと do i=1,4800000; write(iunit) a(i); enddo にしたやつを比較すると、前者は後者の 1/3 くらいのサイズになった。

また、テキスト (form="formatted") 形式についても今まであまり気にしていなかったがこの違いはあり、やはり横に長くした方が 1/3 くらいになる。

一例として、4800000 個の単精度データを吐き出してみた。テキストの場合、フォーマットは 1x,es13.6 にしてみた。単にバイナリとあるのは form="unformatted", actionaccess="sequential" のこと。

  • テキスト(縦長): 68,688 KB
  • テキスト(横長): 24,403 KB
  • バイナリ(縦長): 56,250 KB
  • バイナリ(横長): 18,751 KB
  • バイナリ (actionaccess="stream"): 18750 KB
まずわかるのは actionaccess="stream" (ifort でいう form="binary")は横長の action="sequential" とほとんど変わらない、ということ。

それに、横長テキストもかなり小さいので、こっちでも別にいいかなと思える。…が、横長テキストってフォーマット指定時に繰り返し回数のところに変数が使えないもんだから、横に並ぶデータの個数をハードコーディングしないとダメなんだよね(…たぶん。違ってたら教えて…)。どういうことかというと…たとえばデータの個数が imax = 4800000 だったとして、

  write(iunit, "(imax(1x,es13.6))") ( a(i), i=1,imax)

とはできないので、

  write(iunit, "(4800000(1x,es13.6))") ( a(i), i=1,imax)

とするしかない(ようだ)、ということ。

再度結論

したがって、再度結論をまとめると、
  • 中身を確認したいような場合: 縦長テキスト形式(横長だと重すぎて開けなくて意味ない)
  • 後で流れ場の処理とかしたいから出しとく、みたいなの: 横長のバイナリ (actionaccess="sequential")
  • FV用の Plot3D: バイナリ (actionaccess="stream")
としようと思う。


(最終更新 16:51)
(2015-10-10 typoを修正: action→access)

2015-01-17

FIELDVIEW で Plot3D の binary 読み込む

いちおうメモしとく

FV12.3 の reference manual pdf には "Binary files can only be written and read using C." とあって、 Fortran の場合は form="unformatted" にしろという感じ。だが、実際にやってみたらなぜかそっちだとうまくいかず、 form="binary" にして、読み込み時に Binary を選択するとうまくいった。なお精度は real( foo, 4 ) で単精度に落としている。可視化だから倍精度の意味ないし。ファイルサイズ半分くらいになった。今まで倍精度で書き出してたのアホすぎ…。

FV13 の Auto-Detect format も、もちろん問題なし。

計算環境は CentOS 6 (64 bit) + ifort 12 or 13 (x86_64). FV は Win.

2014-10-04

minloc, minval (maxloc, maxval) について再度自分用まとめ。サンプルつき

これ何度目だよって感じだが忘れやすいので…

2次元配列 a(i,j) について考えてみよう。もっと具体的にするか…

a =
i  / j →

 |   1  2   3  0 |     |(1,1) (1,2) (1,3) (1,4)|
 |   5  6   7  8 | ... |(2,1) (2,2) (2,3) (2,4)|
 |   9  8   0  6 |     |(3,1) (3,2) (3,3) (3,4)|
 |  -3  4  -1  2 |     |(4,1) (4,2) (4,3) (4,4)|

としよう。

val:

  • 無指定 → 返り値はスカラ。minval( a ) で配列全体の最小値。 minval( a ) = -3.
  • dim を指定 → 返り値は配列。minval( a, dim=1 ) なら、各列ごとの最小値。minval( a, dim=1 ) = ( -3, 2, -1, 0 )

loc:

  • 無指定 → 返り値は1次元配列(ここを勘違いしてた)。今は2次元配列なので、要素は2つ。考えたら当たり前で、ここに入ってる値ってのが ( i_location_a_is_min, j_location_a_is_min ) ということ。そりゃそうだ…。minloc( a ) = ( 4, 1 ).
  • 当然、3次元配列なら ( i_minloc, j_minloc, k_minloc ) の3要素が入った1次元配列になる。
  • dim を指定 → 返り値は配列。次元は今の場合 2-1 = 1 になる。意味は「各列で最小の値のj位置」になる。つまり minloc( a, dim=1 ) = ( 4, 1, 4, 1 ) となる。i 位置の情報はシーケンシャルというところで入ってるので省略されるわけか…。

サンプルコード

ただし、古い g95 では minloc のところがランタイムに segfault になる。-Wall, -Wextra などはスルーされる。$ g95 -v で 2010 なら多分アウト。バグだったっぽい。gfortran か ifort で試すのがベター。

program test_val_loc
  implicit none
  integer :: a(4,4)

  a(1,1) = 1
  a(1,2) = 2
  a(1,3) = 3
  a(1,4) = 0

  a(2,1) = 5
  a(2,2) = 6
  a(2,3) = 7
  a(2,4) = 8

  a(3,1) = 9
  a(3,2) = 8
  a(3,3) = 0
  a(3,4) = 6

  a(4,1) = -3
  a(4,2) = 4
  a(4,3) = -1
  a(4,4) = 2

  !! val
  write(*,"('minval( a ) = ',i2)") minval( a )
  write(*,"('minval( a, dim=1 ) = ',4(i2,1x))") minval( a, dim=1 )
  write(*,"('minval( a, dim=2 ) = ',4(i2,1x))") minval( a, dim=2 )

  !! loc
  write(*,"('minloc( a ) = (i_minloc,j_minloc) = (',i2,',',i2,')')") minloc( a )
  write(*,"('minloc( a, dim=1 ) = ',4(i2,1x))") minloc( a, dim=1 )
  write(*,"('minloc( a, dim=2 ) = ',4(i2,1x))") minloc( a, dim=2 )

  stop
endprogram test_val_loc

2014-08-27

Fortran でインラインコメントの intent(in/out/inout) を1行に複数書く

今までは Fortran で何かの subroutine を call するとき、

  call subr( &
      &   n       = n &       !! intent(in)
      & , mat_in  = mat_in &  !! intent(in)
      & , mat_out = mat_out & !! intent(out)
  & )

のように書いていた(いる)。コロンの位置が気持ち悪いというのはよく言われるが、今はそこは関係ない(理由は、行単位でのコメントアウトや移動が楽なため)。注目すべきは右にあるインラインコメントによる intent の明示。この書き方、引数が多い時は確かに誤解の余地がなくていいのだが、引数が少ない時は若干煩雑だ。引数3つくらいまでは1行で書いてしまいたい。しかし、引数が2つ以上あるとき、1行にしてしまうと intent(in) がひとつしか書けないのが問題だった。…と思っていた。思いこんでいた。思いこみコワイ。

  call subr( n, mat_in, mat_out ) !! intent(in, in, out)

これでいいじゃん!あるいはセミコロンでもいいか:

  call subr( n, mat_in, mat_out ) !! intent(in; in; out)

C言語系の人にしたらセミコロンは気持ち悪そうだが。

UPDATE 2014-12-03
引数が多いけどそれぞれが短めのとき、

call prep_nc_nf( i, j, nxf, ind,  nc, nf_SW, nf_SE, nf_NW, nf_NE )
!!       intent(in, in, in,  in, out,   out,   out,   out, out   )

とするのを思いついた。これくらいになると安全のために = (イコール)を使いたくなるが…まぁC言語屋さんにはこっちのほうがわかりやすいのかなとか。

2013-12-10

全員に共通する環境設定 (e.g. ifortvars.sh 的なもの)は /etc/profile.d/ に書く!

以前

ifort の環境変数設定は .bashrc に書くのでよさそう、なんだが…

ということで ~/.bashrc を使うと更新が面倒、というエントリを書いたが、アホだった。自動化できた。以下その方法。

まず

$ su -

して、

# vim /etc/profile.d/myifort.sh

みたいな適当なスクリプトを作成し、そこに

source /opt/intel/bin/compilervars.sh intel64

と書けば終了!

あとは一旦ログオフ→ログインすればOK.

なんで気づいたかっていうと、 ~/.bashrc にデフォルトで
# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi
って書いてあって、あれ?これって自動設定じゃね?と思って /etc/bashrc を見ると /etc/profile.d を使えよカスが、とあった。

参考:
profile.d でググると出てくるよ


----
UPDATE 2014-09-21
.bashrc も完全に無意味ということもないなと気づいたのでメモ。

いま現在、ver 2013.5.192 を使っている。だが、2015 が出るほど SP1 が枯れてきたので、試したい。そこで、 profile.d の方はいじらずに、自分だけ設定を変えたい。ということで、.bashrc に

source /opt/intel/composer_xe_2013_sp1.4.211/bin/compilervars.sh intel64

と書いて、ログオフ→ログイン。$ echo $PATH や $ ifort -V で確認すると、ちゃんと 2013_sp1.4.211 の設定が読まれていた。やっぱりやめたいときはこの行をコメントアウトするだけでいいので、楽。







2013-08-06

ifort で最近良く使うコンパイルオプション

ifort 2013 @ Linux の話。OpenMP 使う前提。使わない場合も -openmp を抜くだけで同じだと思うが。

メモリいっぱい使うとき


$ ifort foo.f90 -mcmodel=medium -openmp -shared-intel

なお、-shared-intel にすると -fast が使えない(-fast が -static を含むため。-fast の実態は複数のコンパイルオプションへのエイリアス。ifort -help opt を参照)。そこで最適化は

$ ifort foo.f90 -xHost -Ofast -ipo -mcmodel=medium -openmp -shared-intel

にする。要は -fast から -static を抜いたかたち。本番計算はこれでやってる。

デバッグ(ランタイムエラーを拾う)用


$ ifort foo.f90 -CB -traceback -g

なんだけど、実行が死ぬほど遅いから、実際には

$ ifort foo.f90 -CB -traceback -g -xHost -Ofast -ipo -mcmodel=medium -openmp -shared-intel

と全部入りにする。ただ、これやるとコンパイルがだいぶ遅くなるので場合によっては

$ ifort foo.f90 -CB -traceback -g -mcmodel=medium -openmp -shared-intel

だけにする(-O2の意味)。


UPDATE 2013-10-11

-shared-intel は、昔は -i-dynamic という名前だったようだ。ifort 11 まで、なのかな?
それから、-mcmodel=medium とイコールにしても、 -mcmodel medium と半角スペースにしてもどちらでも通るようだ。公式にはイコールになってる ので自分はイコールにしてるけども。
[/UPDATE]

ifort の環境変数設定は .bashrc に書くのでよさそう、なんだが…

UPDATE 2013-12-10: このエントリは obsolete です。

全員に共通する環境設定 (e.g. ifortvars.sh 的なもの)は /etc/profile.d/ に書く!

を見て下さい。

以下、古い無意味な記述
----
そもそも、こんなことを2013年にもなって初めて知ったとか絶望するけどしょうがない。ちなみに、これまではどうしてたかっていうと

$ su -
# ln -is /opt/intel/composer_xe_2013.4.183/bin/intel64/ifort /usr/bin/ifort

とかしてシンボリックリンク作ってた。ユーザは何も設定しなくてよかったわけ。ただ、これだけだと -shared-intel のときにリンク切れするのでいちいち ldd して手動で切れてるリンク繋いでた。

----
各人がホームディレクトリ(つまり ~ )において

$ vim .bashrc

して設定…今の場合は、

source /opt/intel/composer_xe_2013.4.183/bin/compilervars.sh intel64

を書いておく。でいいんだと思う。ただ、各人に書かせるのは死ぬほど面倒っていうか絶対やらない奴がいるので、

  1. root が全員の .bashrc にコピペして回る ← やっぱり死ぬほど面倒
  2. root が /etc/skel に書いておいてから useradd するのがよさそう

参考:
http://www.atmarkit.co.jp/flinux/rensai/linuxtips/311newuserdef.html
http://www.artsnet.jp/archives/482

ただ、今後導入する計算機なら 2. でいいけど、既存のユーザには影響しないからやっぱり 1. もやらんといけないか。メンドイ。

…あっ。これ、コンパイラがアップデートするたびに「composer_xe_2013.4.183」のところ書き換えないとだめじゃん死んだ。他の研究室ではどうしてるんだろう?アップデートのたびに全員にMLで「.bashrcを書きかえてください。書きかえないと不幸なことがおきますよ。発散する呪いがかかりますよ。あれあれ?いいんですか(ry」って送ってるんだろうか?

2013-04-08

ライブラリが見つからないと言われたので ldd でリンク先を調べてリンクした

先輩からもらったコードを自分のコードにマージしてコンパイルするとなんかエラーが出た。
$ ifort -fast foo.f90
は問題ないのに -fast を外すとエラーになる。どうも -static が必要っぽい。ググると、

relocation truncated to fit: R_X86_64_PC32

がヒット。よく読んでないけど(読んでも意味がわからん)、下の方にあるコメントで "-mcmodel medium -shared-intel" を付けろとあるので付けてみた。
$ ifort -O1 -mcmodel medium -shared-intel foo.f90
するとコンパイルは通った。ただ、実行しようとするとライブラリが見つからないとか言われる。

そこで、こないだ覚えた
$ ldd a.out
をしてみると、
        linux-vdso.so.1 =>  (0x00007fff657f3000)
        libifport.so.5 => not found
        libifcore.so.5 => not found
        libimf.so => not found
        libsvml.so => not found
        libm.so.6 => /lib64/libm.so.6 (0x0000003091400000)
        libintlc.so.5 => not found
        libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003091000000)
        libc.so.6 => /lib64/libc.so.6 (0x0000003090800000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003092400000)
        libdl.so.2 => /lib64/libdl.so.2 (0x0000003090c00000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003090400000)
という感じになった。ので、
$ su -
して、 not found と言われたもののシンボリックリンクを作った:

# ln -is /opt/intel/lib/intel64/libifport.so.5 /usr/lib64/libifport.so.5
# ln -is /opt/intel/lib/intel64/libifcore.so.5 /usr/lib64/libifcore.so.5
# ln -is /opt/intel/lib/intel64/libimf.so /usr/lib64/libimf.so
# ln -is /opt/intel/lib/intel64/libsvml.so /usr/lib64/libsvml.so
# ln -is /opt/intel/lib/intel64/libintlc.so.5 /usr/lib64/libintlc.so.5
んで再度
$ ldd a.out
すると、ちゃんと全部見つかって、実行できた。ldd 便利。

2013-04-01

配列を intent(out) で返したつもりが一部しか返っていなかった

Fortran 90で配列の上下限を省略してコロンを使うことについて にやや関連した話題。

まず、呼び出し側の配列として

  real(8) :: x(201,3)

というものがあって、subroutine 側に対応する

  real(8), intent(out) :: c(51,3)

というのがあった。んで、subroutine を

  call sub( c = x )   !! intent(out)

という風に call していた。このとき、

  x(1:51,1:3) = c(1:51,1:3)

のように値が入ってくれるのだろう、と、勝手に思っていたが、恐るべきことに実際には、

  x(1:51,1) = c(1:51,1)

となっていた…(戦慄)。これがもし

  x(1,1) = c(1,1)

だけだったらさすがにすぐ気づいたんだろうけど、なぜか第1次元は全部埋まっていたので発見が遅れた。


解決方法を4つ考えた。

1. ダミー配列を用意する
つまり
  real(8) :: tmp(51,3)
というのを用意しておき、
  call sub( c = tmp )   !! intent(out)
  x(1:51,1:3) = tmp(1:51,1:3)
とする。わかりやすいが、計算リソースを食う。

2. call 時に上下限を指定する。
つまり
  call sub( c = x(1:51,1:3) )   !! intent(out)
ということ。ちょっとわかりにくい。

3. subroutine 側の配列のサイズを呼び出し側に合わせる
つまり
  real(8), intent(out) :: c(201,3)
とする。使わない分まで確保するため、メモリの無駄。だが、今まで一番多くやってたのはたぶんこれ…。実際には 201 という数値ではなくて、変数になっていて、一緒に intent(in) して割付、というのを最近はけっこうやっていた。

4. subroutine 側の配列を assumed shape にする。下限を指定する。
つまり
  real(8), intent(out) :: c(:,:)
としておく。これが一番一般的なのかな。パフォーマンスに若干影響するとかしないとか見かけた気がするけど気のせいかもしれない。この方法は楽だけど、下限が1でない配列を使う時は下限がずれる可能性があり、危険。下限だけ指定するのがいいかもしれない。

参考:
http://d.hatena.ne.jp/rontas/20130113/1358047540
このブログの Fortran カテゴリは自分が知らなかったことばかりでためになった。


これまでの自分は基本的に 1 か 3 を使っていたが、徐々に 4 に移行すべきなのかもしれない……。というか、実際にちょっと使い始めてみたけど、2 と 4 は併用するものかも。

2013-03-29

minloc, maxloc の結果は「配列の下限から数えて何番目か」だった

Fortran の話。たとえば、

real(8) :: array(2:11)

  do i=2,11
    array(i) = dble( i )
  enddo

の場合は maxloc( array, dim=1 ) = 11 になると思っていたが、実際には 10 になる。下限が 0 や負の時も同様。

2012-12-02

Fortran で call system() するときに変数 (variable) を渡す方法

たとえば、do i=1,100 というループを回していて、各ステップごとに毎回 mkdir i をしたい、しかも 1, 2, ... ではなく 001, 002, ... というフォルダ名で作成したい、ということがある。というかあった。無理か?と思ったが、できた。
Variables as arguments in Fortran 77
http://www.linuxforums.org/forum/programming-scripting/154686-variables-arguments-fortran-77-a.html
つまり call system() を使うことは使うが、文字列を用意して、そこにコマンドも含めて何もかも内部入出力で書き込んでしまうという力技。

具体的には、

program test
  implicit none
  integer :: i
  character(len=72) :: command
  !! -----------------------------

  do i=1,100
    write(command,"('mkdir ',i3.3)") i !! コマンドごと書き込む
    call system(command) !!
  enddo

  stop
endprogram test

ということ。

自分は実際には、mkdir_if_not_exist.sh という、そのディレクトリがあるかどうかを調べてないときだけ作るスクリプトを作って、それを呼び出している。それの中身はこんな感じ:

mkdir_if_not_exist()
{
  echo -n "Checking if $1 directory exists... "
  if [ ! -d $1 ] ; then
    echo -n "... the directory does not exist ... Making a directory $1... "
    mkdir $1
    echo "... done."
  else
    echo "... the directory already exists."
  fi
}

これの参照元は、いろんなページを参考にした気がするがメモるの忘れてたかも…(はてブには残ってるだろうが)。まぁこの程度なら著作物性はなさそうなのでいいかな…?

なお、シェルスクリプトファイルを置いているのは実行ファイル(a.out 的な)よりも一つ下の ./src の中であり、また、ディレクトリを作りたいのは ./output の下なので、上記の内部入出力 write 文のところは実際には、

  write(command,"('sh ./src/mkdir_if_not_exist.sh ./output/',i3.3)") i !! コマンドごと書き込む

という感じにしている。

2012-09-29

syntax highlighting for Fortran 90 in Notepad++

Fortran 90 用 userDefineLang.xml

Notepad++ には FORTRAN 77 用の syntax highlighting はデフォルトで用意されているが、Fortran 90 用のものはない。そこで、適当にそれっぽいものを作って使っている。stylers.xml の Fortran の部分を元にして(コピーして)いる。

公開してもたぶん怒られることは無いと思うので、google drive にアップロードしてみた:

https://script.google.com/d/1aUinLB-CF0shKweVTWuqjFQ3__o4Q6f-HtgfpTSn8qwmLegs4jol3dqP/edit

これをコピーして、"userDefineLang.xml" という名前のテキストファイルとして保存し、notepad++.exe と同じフォルダに放り込む。Notepad++ を起動すると、メニューの Language の下の方に Fortan90 と Fortran90_bk というのができているはず。

Fortran90_bk の方は、黒背景を想定したもので、メニューの
Settings > Style Configurator... > 上の方の Select theme ドロップボックス
で、「Deep Black」を選ぶとそれっぽくなるはず。自分は最近はこれを使っている。

関連付けについて

上のファイルをそのまま使うと、関連付けがうまくいかない可能性がある。というか、順番で先に来ている Fortran90 の方になってしまうっぽい。Fortran90_bk を使いたくて、これを変えるには、以下のようにする。

ツールバーの「User-Defined Dialogue...」というボタンを押してダイアログを開き、上の方の「User language:」から Fortran90 を選ぶ。右のほうに「Ext.:」というフィールドがあり、f90 と入っている、はず。これを消す。一方、Fortran90_bk の方の「Ext.:」には f90 と入っていることを確認する。右上の×ボタンでダイアログを閉じる。これで次からは関連付けが _bk の方になる、はず。

設定の変更

色や単語、書体などの設定は好みが大きいだろうから、上記ダイアログから自分好みに変更すればいいと思う。

フォントについて

自分は Style Configurator > Global Styles > Global override において、Font style は BDF UM+, Font size は 9(BDF UM+はこれしか選べない), Enable global font と Enable global font size をオン、としている。DejaVu Sans Mono にしたいところだが、日本語のコメントが文字化けするので……。

……と思っていたが、いまやってみたらコメントだけ日本語フォント化できた。手順をメモしておく。

まず
Style Configurator > Global Styles > Default Style > Font Style > Font name:
で DejaVu Sans Mono など、好きなフォントを選択し、「Save & Close」ボタンで閉じる。もちろん、Global override は切っておく。

次に、「User-Defined Dialogue...」ボタンでダイアログを開き、「User language:」からスタイルを選び、「Comment & Number」タグを選択。上の方の Comment Line > Font Style > Font Name: で日本語フォントを選ぶ。ひとまず「MS ゴシック」にしてみた。メイリオもいいな……。

上の google drive のリンク先にも MS ゴシック を選択した状態の xml ファイルを反映してみたが、もしうまくいかなければ(あるいはフォントを変えたければ)この方法で変更できる。

検索結果 (Find result) ウィンドウ内のスタイル

気づきづらかったので、ついでにメモ。Style Configulator の Language: で下から二番目の Search result がそれ。わかりづらすぎだろ……。しかも、HIT WORD というのが実際には行番号のスタイルで、KEYWORD1が検索した単語(つまりHIT WORD)だし。ちょっとおかしい。あとこのウィンドウって×ボタン以外で閉じれないんだろうか。

2012-05-12

自動配列の割付で謎の segmentation fault @ ifort

[2012-05-12追記] これたぶん結局 ulimit -s で解決した話だったと思うので、http://naturesflyers.blogspot.jp/2009/12/ulimit.html も参照。現状、-heap-arrays なんて使ってないし、全部 allocatable に置き換えたりもしてないので。

---
   real(8) :: pt(1:xyz+3, -1:i_max+1, -1:j_max+1, 0:k_max+1)

っていう自動配列の割付がなぜかうまく行かず。 i_max, j_max, k_max を他のに変えるとうまく行く。こいつの上下でも、i_max, j_max, k_max という変数を使った割付はしまくっているので、意味不明。さらに謎なのが、g95 で -ftrace=full -fbounds-check を付けても、問題なく通るという事実。ちなみに ifort 10 でも 11 でも同様。

結局、下記を参考に、 -heap-arrays オプションを付けると通った。

http://wind.geophys.tohoku.ac.jp/~sawada/linux/intel.html
http://wind.geophys.tohoku.ac.jp/nonhydro/toolbox/How2NhmV2R0_ifort.txt

これがなんなのかだが、
-heap-arrays[-]
自動配列および一時的な計算用に作成される配列を、スタックではなくヒープ上に割り当てるように指示します。
とのこと (from  http://www.xlsoft.com/jp/products/intel/compilers/fcl/10.1/Release_Notes.htm )。
「あ゛?」って感じで、正直、ヒープ領域とスタック領域って聞いたことはあるけど何がどう違うのってのはよくわからん。

 とりあえず、気象庁コーディングルールに(やっぱり)載ってたのを発見:
自動配列はメモリのスタック領域を使用する場合が多く、ヒープ領域を使用す る場合が多いallocatable 配列より自動配列の方が割付を高速に行えることが多 い。しかし、使用可能なスタックのサイズに制限がある場合があり、自動配列で 使用できるメモリが制限される場合がある。(OS・コンパイラによる。)
まさにこれじゃね?どうも「使用可能なスタックのサイズ」ってやつの限界まで自動配列で割り付けちまったらしい。g95 ではその「サイズ」ってのが違うんだな(?)。

こちらのページにも同じことが・・・(正しくは「わかりずらい」→「わかりづらい」だがそんなことはどうでもいい)
このバグは実行時に非常に分かりずらい形で現れるため,codingの際にルールとしてallocatableで宣言するようにした方がいいと思う.
from: http://locs.bw.nitech.ac.jp/~kobayashi/programming.html

そっか、allocatable の方が結局いいのか・・・ orz

お、そしてここのリンク先でやっとスタックとヒープがわかりそうな予感(今から読む
http://asp.mi.hama-med.ac.jp/comp-basic/memory/

----
うーん。
  a. -heap-arrays で押し通す
  b. allocatable + de/allocate に(なるべく)変える
・・・こんなのおれのコーディングミスとは言えないんだからコンパイル側で何とかしてほしいよなぁ。ってことでとりあえず a. で。結果変わったり遅くなったりしたら泣けるが・・・。

と思ったけど、やっぱ allocatable にしよう。ただし、気象庁コーディングルールに従って、「値がどんどん変わる変数については、global にはせず、引数で渡してゆく」のは徹底しよう。

----
あと一般に参考になるサイトを追加っつーかメモ:

http://www.nag-j.co.jp/fortran/index.html
http://jujuohoh.hp.infoseek.co.jp/tips/index.html

2012-05-07

スタック領域のサイズを変更したりする ulimit

大きなサイズの配列を確保しようとして segmentation fault になった。
後輩だったか誰かの情報で ulimit が怪しいときいた。
これ:
http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230911/

使うのはたぶん
$ ulimit -a

$ ulimit -s unlimited (か、適当に大きめの数字)
だろうか。これで segmentation fault が解消すればいいんだが・・・。
⇒ 解決した。

よかった。が、何回か試しに設定を変えていたら、「許可されていない操作です」とか怒られた。


http://d.hatena.ne.jp/ymotongpoo/20080109/1199881689
とのこと。ssh をいじるのはなんか嫌なので放置。ログインしなおした。
最初から上げておくこともできるようだが、メンドイしとりあえずこれでいいや。

----
追記:
結局、
$ su -
してからの
# vim /etc/profile
に上限を(?)、
# vim /etc/bashrc
にデフォルト値を(?)書いている。
値はいずれも適当に大きめな値にしてる。
いまいちこれらの違いわかってないけど…。


Update 2014-10-06

https://software.intel.com/en-us/articles/intel-fortran-compiler-increased-stack-usage-of-80-or-higher-compilers-causes-segmentation-fault/

http://www.isus.jp/article/fortran-special/sigsegv-or-sigbus-errors/

あたりが参考になる。
ただし、後者のリンク先含め色々なところで unlimited にせよとあるが、それではダメだという経験があった。前者のリンク先には
Linux: The size of "unlimited" varies by Linux configuration, so you may need to specify a larger, specific number to ulimit (for example, 999999999).
とあるので、この経験則が裏付けられたようだ。大丈夫な場合もあるということにはなるが…。

2012-03-22

OpenMP のメモ

お勉強
牛島先生の本読んでる。

ワークシェアリング
  • do -> do をワークシェア。schedule必須か?
  • sections -> ブロックをワークシェア
  • single -> 単一スレッドだけにさせる(読み込みとか)。copyprivateでブロードキャスト
  • workshare -> 代入をワークシェア?

threadprivate
  • 変数にsave属性付けないとコンパイラに怒られる
  • というかthread数のdynamicしたらダメなので使うことないかも?(dynamicたぶんONにすると思う)

具体的な使い方
ソースはもうあるとする。

コンパイル
$ ifort foo.f90 -fast -openmp -static-intel
みたいな感じ。

[2013-03-14追記]
-static-intel を付けないと、
error while loading shared libraries: libiomp5.so: cannot open shared object file: No such file or directory
と怒られた。ちょっとググッた結果、su - してから、
# ln -is /opt/intel/lib/intel64/libiomp5.so /usr/lib64/libiomp5.so
とシンボリックリンクを置いておくことで解決した模様。まぁ実行ファイルサイズ別にでかくてもいいので毎回 static にしちゃえばいいか。

この課程で知ったコマンド ldd と file がなんか便利そうな感じ。ldd a.out とするとちゃんと missing とかでていた。
http://www1.tmtv.ne.jp/~saekisan/Documents/file_ldd_.txt
とかにはやたら詳しい解説がある…けどチラ見しただけ。
[/追記]


実行
環境変数をセットしてから走らせる。
$ export OMP_NUM_THREADS=8
$ ./a.out
みたいな感じ。

一行目は、
$ OMP_NUM_THREADS=8
$ export OMP_NUM_THREADS
と分けても同じようだ。

2011-04-17

Fortran 90で配列の上下限を省略してコロンを使うことについて

http://www.nag-j.co.jp/fortran/FI_12.html
受け取る側では以下のようにコロンを用いた記述を行い、どのような大きさであっても 受け取れる用に記述します
とか知らなかった…ショック。
うーんでも明示してあったほうが読みやすいかな?
あと size(x) も使える場面ありそうだなぁ…。


追記:
どうもコロンでやってしまうと subroutine 側では勝手に 1: になってしまうようだ。危なすぎ。当然使用禁止だわ。

たとえば

real(8) :: hoge(2:3)

があって、これを

call fuga( hoge = hoge ) !! intent(in)

と読ませたとする。このとき、

subroutine fuga( hoge )
  real(8), intent(in) :: hoge( : )
  
  write(*,"('hoge(',i2,':',i2)')") lbound(hoge,1), ubound(hoge,1)
  
  return
endsubroutine

とすると、
hoge( 1: 2)
と出力される。めっちゃ危険じゃん…。


[2013-04-01追記]
「下限だけ指定してコロン」が最強かも。

参考:
http://d.hatena.ne.jp/rontas/20130113/1358047540
[/追記]


[2012-11-19追記]
ついさっき、これと似てるけどちょっと違うミスをしていた。若干簡略化して以下に説明する。

まず呼び出し側では、

integer, parameter :: imax=100
integer, parameter :: jmax=100
real(8) :: po(-1:imax+1,-1:jmax+1)

  call subroutine1( pt = po(:,:) ) !! intent(in)
<以下略>

のように書いていた。でもって呼ばれる側は、

subroutine1( pt )
implicit none
real(8), intent(in) :: pt(imax,jmax)
<以下略>

としていた。意図としてはもちろん、pt(1:imax, 1:jmax) = po(1:imax,1:jmax) であってほしかった。ところがこの場合、g95 でも ifort (ver13) でも pt(-1:imax-1,-1:jmax-1) が入ってしまう。正しくは、

  call subroutine1( pt = po(1:imax,1:jmax) ) !! intent(in)

とすべきだった。あるいは、配列をケチらずに

  real(8), intent(in) :: pt(-1:imax+1,-1:jmax+1)

と書いてもよかった。いずれにせよ、配列の一部だけを渡すときは要注意、ということだ。
[/追記]

2010-11-22

f90 mode @ emacs

いろいろ便利そうだがカスタマイズとか使い方を忘れそうなのでメモっていく

emacs のアーカイヴを解凍したフォルダ内に /lisp/progmodes/f90.el があるはずなので、使い始めるための設定などは特に不要で、foo.f90 的なファイル名のソースコードを読み込めば自動的に起動する。

カスタマイズ
まずカスタマイズだが、f90.el の上の方のコメントにあるように、下記を init.el (人によっては .emacs とか .emacs.el )に加えればよさそう。実際にはこれ全部を書く必要はなく、デフォルト値から変えたいところだけ書けばいい。



;;(add-hook 'f90-mode-hook
;;      ;; These are the default values.
;;      '(lambda () (setq f90-do-indent 3
;;                        f90-if-indent 3
;;                        f90-type-indent 3
;;                        f90-program-indent 2
;;                        f90-continuation-indent 5
;;                        f90-comment-region "!!$"
;;                        f90-directive-comment-re "!hpf\\$"
;;                        f90-indented-comment-re "!"
;;                        f90-break-delimiters "[-+\\*/><=,% \t]"
;;                        f90-break-before-delimiters t
;;                        f90-beginning-ampersand t
;;                        f90-smart-end 'blink
;;                        f90-auto-keyword-case nil
;;                        f90-leave-line-no nil
;;                        indent-tabs-mode nil
;;                        f90-font-lock-keywords f90-font-lock-keywords-2
;;                  )
;;       ;; These are not default.
;;       (abbrev-mode 1)             ; turn on abbreviation mode
;;       (f90-add-imenu-menu)        ; extra menu with functions etc.
;;       (if f90-auto-keyword-case   ; change case of all keywords on startup
;;           (f90-change-keywords f90-auto-keyword-case))
;;       ))



自分の場合 flymake も使いたいのと、インデントの設定が気にくわないのでちょっといじった。

<ここに自分の設定をコピペすること>


コマンド

以下、コマンドの使い方を書いていく予定

f90-break-line
いまいる位置で現在行を次の行に分割・インデントして、しかも自動で & と & を挿入してくれるっぽい。すげー

2010-07-07

How to uninstall ifort (on CentOS)?

方法

uninstall.sh みたいなスクリプトが用意されているので、root で実行する。だいたい下記のような感じ。細かいところはインストール時の構成によって若干変わってくると思う。

場所

ver 10

# /opt/intel/fce/[version]/bin/uninstall.sh

ver 11.1, build 072

# /opt/Compiler/11.1/072/bin/intel64/uninstall_cprof.sh
# /opt/Compiler/11.1/072/bin/intel64/uninstall_debugger.sh
このときはもともとデバッガと別々にインストールしていたのかも。

ver 2011, update 11

# /opt/intel/composer_xe_2011_sp1.11.339/bin/uninstall.sh

2010-07-06

$g95 source.f90 -Wextra

-Wextra オプションまじアツい

interface module (interface block) のテンプレ @ F90

あまりにもよく忘れるので

! interface module
module my_inter
  
  ! interface block
  ! すべての subroutine の冒頭部分と仮引数宣言をコピペする。
  ! subroutine 側で引数の名前や数を変えたら、
  ! こちらにも反映させないといけない(正直メンドイ)。
  ! そのかわり subroutine を module に入れなくても F90 化できる

  interface
    
    subroutine sub1( int, char, real_arr )
      implicit none
      integer, intent(in) :: int
      character(len=24), intent(in) :: char
      real(8), intent(out) :: real_arr(0:) !下限のみ指定する形状引継ぎ配列
      integer :: i, j, k
    endsubroutine sub1

    subroutine sub2
      ...
    endsubroutine sub2

  endinterface
  
endmodule my_inter

でもって、call する側の subroutine では、普通の module のときと同じように、

subroutine sub3
  use my_inter, only : sub1 ! これでsub1が利用可能に
  implicit none
    ...
    call sub1( &
      &   int = int & ! intent(in)
      & , char = char & ! intent(in)
      & , real_arr = real_arr & ! intent(out)
    & )
    ...
  return
endsubroutine sub3


みたいに使う。