ユーザ用ツール

サイト用ツール


fortran:tips

差分

この文書の現在のバージョンと選択したバージョンの差分を表示します。

この比較画面にリンクする

次のリビジョン
前のリビジョン
fortran:tips [2013/12/22 18:28]
saito created
fortran:tips [2017/10/03 12:55] (現在)
ライン 1: ライン 1:
 ====== tips ====== ====== tips ======
 +  * intelのコンパイラは[[fortran:​ifort]]参照のこと.
 +  * [[http://​www.owlnet.rice.edu/​~ceng303/​manuals/​fortran/​]] が役に立ちそう.
 +  * 
  
 +===== よくある間違い =====
 +コーディングにおいてよくある間違いをまとめる.
 +
 +==== べき乗の順序 ====
 +<​nowiki>​計算の優先順位は
 ++- < */ < **
 +である.</​nowiki>​
 +<code fortran>
 +print*,​-1**0
 +</​code>​
 +<​nowiki>​
 +これは-(1**0)と解釈されるので,出力結果は−1.
 +-1に対してべき乗する場合は,(-1)**0.
 +</​nowiki>​
 +
 +==== 論理演算の順序 ====
 +<​nowiki>​
 +論理演算子の優先順位は
 +.eqv., .neqv. < .or. < .and. < .not.
 +である.
 +</​nowiki>​
 +<code fortran>
 +logical :: a=.false.
 +num :: i=1
 +if(a.eqv..false..or.i==1) then
 +print*,'​if'​
 +else
 +print*,'​else'​
 +end if
 +</​code><​nowiki>​
 +これは,a.eqv.(.false..or.i==1) と解釈される.
 +(.false..or.i==1) はtrueなので,上のコードはelseを吐き出す.
 +前後の条件をorでつなぐ場合は,
 +if((a.eqv..false.).or.(i==1)) としてカッコで順序を明示する.
 +</​nowiki>​
 +
 +ちなみに ​  
 +  * (.ture..or..false.)は.true.(どちらかが真なのでtrue)
 +  * (.ture..and..false.)は.false.(どちらも真でないのでfalse)
 +になる.
 +===== allocated =====
 +すでにallocateしたかどうかわからない時は,allocatedで確かめてからallocateする.
 +https://​gcc.gnu.org/​onlinedocs/​gcc-4.1.0/​gfortran/​ALLOCATED.html
 +<code fortran>
 +  if (allocated(x).eqv..false.) allocate(x(n))
 +</​code>​
 +===== construct name =====
 +入れ子のループで,cycleやexitを使って外側に飛びたいときは,do ループにラベルをつける.
 +これで文番号を付けずに好きなところへ飛べる.
 +  - do の前にラベルとコロンをつける.
 +  - cycleやexitの後にラベルをつける.
 +  - end do の後ろにラベルをつける.
 +
 +<code fortran>
 +outer : do i=1,n
 +  do j=1,n
 +    if(...) cycle outer
 +  end do
 +end do outer
 +</​code>​
 +
 +
 +===== 読み込み専用,書き込み専用で開く =====
 +読み込み専用で開く場合.
 +<code fortran>
 +open(10,​file='​input.dat',​action='​read'​)
 +</​code>​
 +その他,action='​write',​ action='​readwrite'​もある.
 +===== コンパイラオプション =====
 +
 +  * プログラム作成段階においては,配列外参照,暗黙の型宣言,浮動小数点演算例外の検出はつけてコンパイルした方が良い.
 +  * プログラムが完成して,エラーがない場合には以下のコンパイルオプションはない方が良い.ない方が早く計算できる.
 +
 +^  compiler ​ ^  gfortran ​ ^  ifort  ^ 
 +|エラーの検出FIXME|-Wall|-check all|
 +|配列外参照|-fbounds-check|-CB| ​
 +|暗黙の型宣言|-fimplicit-none|-warn declarations|
 +|浮動小数点演算例外の検出|-ffpe-trap=zero|-fpe0|
 +|標準外機能の警告|-std=f95|-std|
 +
 +例えば以下のようにする.
 +<code bash>
 +gfortran filename.f90 -O2 -stand f03 -assume realloc_lhs -check all -traceback -warn all -fstack-protector -assume protect_parens -implicitnone
 +</​code>​
 +===== 連番のファイル名をつける。 =====
 +ファイル名をcharacter変数に代入して使う。ファイル名の変更にはwrite文を使う。
 +逐次計算に使える。
 +<code fortran>
 +character(len=12) filename
 +...
 +do i=1,100
 +  ...
 +  write(filename,'​(a,​i4.4,​a)'​) '​hoge',​i,'​.dat'​
 +  open(10,​file=filename)
 +  ...
 +    write(10,*) ...
 +  ...
 +  close(10)
 +end do
 +</​code>​
 +
 +処理は[[movie]]参照のこと.
 +
 +
 +
 +
 +===== makefileでコンパイル その2=====
 +
 +以下の記事は古い.[[fortran:​makefile|別のページ]]を参照せよ.
 +
 +moduleファイルを含む場合,依存関係をはっきりさせる必要がある.
 +依存関係を変えるたびにmakeファイルを書き変えるのは面倒なので,依存関係を見てくれる
 + ​f90_mod_deps.py を使う.
 +
 +http://​lagrange.mechse.illinois.edu/​mwest/​f90_mod_deps/​
 +
 +コンパイル不要のpardisoやompのモジュールを読み込んだり,同一ファイル内に複数のモジュールが存在し循環参照が起きる場合は,f90_mod_deps.py のwrite_depsに以下のように修正.
 +<code python>
 +def write_deps(outf,​ filename, deps, mods):
 +    filebase, fileext = os.path.splitext(filename)
 +#>>>​
 +    loadmod="​MKL_PARDISO.mod"​
 +    if loadmod in deps:
 +        deps.remove(loadmod)
 +    loadmod="​omp_lib.mod"​
 +    if loadmod in deps:
 +        deps.remove(loadmod)
 +#<<<​
 +    outf.write("​%s.o:​ %s\n" % (filebase, " "​.join(deps)))
 +    for mod in mods:
 +#>>> ​
 +        if mod in deps:
 +            deps.remove(mod)
 +#<<<​
 + outf.write("​%s:​ %s\n"
 +    % (mod, " "​.join(deps)))
 +</​code>​
 +
 +以下,Makefile のサンプル.
 +<code bash>
 +TARGET = a.out
 +DEPS=hoge.deps
 +OBJECTS = piyo.o foo.o bar.o main.o
 +F90 = gfortran
 +FFLAGS=-Wall -ffpe-trap=invalid,​zero,​overflow,​underflow -fbounds-check -fimplicit-none -fbacktrace -fopenmp
 +#FFLAGS=-O3 -fopenmp
 +#F90 = ifort
 +#​FFLAGS=-check all -warn all -std -gen_interfaces -fpe0 -ftrapuv -traceback
 +#FFLAGS = -mkl -O3
 +
 +SOURCES=$(OBJECTS:​.o=.f90)
 +
 +.SUFFIXES :
 +.SUFFIXES : .o .f90 .f
 +.f.o:
 + ${F90} -c $< ${FFLAGS}
 +.f90.o:
 + ${F90} -c $< ${FFLAGS}
 +
 +
 +.PHONY:all
 +all: ${DEPS} ${TARGET}
 +
 +${DEPS}: ${SOURCES}
 + python f90_mod_deps.py --output $@ $^
 +
 +${TARGET} : ${OBJECTS} ​
 + ${F90} -o $@ $^ ${FFLAGS}
 +
 +-include ${DEPS}
 +%.o %.mod: %.f90
 + ${F90} -c $< ${FFLAGS}
 + touch $(patsubst %.f90,​%.mod,​$<​)
 +
 +clean :
 + rm ${TARGET} *.mod *.f90~ ${OBJECTS}
 +</​code>​
 +
 +===== makefileでコンパイル =====
 +複数のファイル(サブルーチンetc.)で構成されるプログラムを動かすのに便利.
 +以下の文を「makefile」という名前で作り,コンパイルしたいファイルと同じディレクトリに置く.
 +(以下,main.f90,​ modules.f90[モジュールファイル],​ sub1.f90, sub2.f90をコンパイルする場合)
 +<​code>​
 +TARGET = a.out
 +OBJECTS = modules.o main.o sub1.o sub2.o
 +F90 = ifort
 +FLAGS = -check all -warn declarations -CB -fpe0 -traceback
 +COMMON_MOD = modules.f90 ​
 +
 +.SUFFIXES :
 +.SUFFIXES : .o .f90 
 +.f90.o:
 + ${F90} -c $< ${FFLAGS}
 +
 +${TARGET} : ${OBJECTS}
 + ${F90} -o $@ ${OBJECTS}
 +clean :
 + rm  *.o ${TARGET} *.mod 
 +
 +
 +${OBJECTS} : ${COMMON_MOD}
 +</​code>​
 +あとは,​makeコマンドを打てばコンパイル完了.そして実行(上の例では./​a.outを打てば良い).
 +<​code>​
 +$ make 
 +$./a.out
 +</​code>​
 +また,以下の様にmake cleanで実行ファイル(a.out)及びオブジェクトファイル(*.o)を消去できる.
 +<​code>​
 +$ make clean
 +</​code>​
 +以下,makefileの変数について簡単に説明する.
 +<​code>​
 +TARGET = 実行ファイル名 ​
 +OBJECTS = モジュールファイル プログラムファイル (すべて拡張子は.oとする.)
 +F90 = コンパイラコマンド (gfortranを使うなら「gfortran」)
 +FLAGS = コンパイラオプション
 +COMMON_MOD = モジュールファイル (拡張子は.f90)
 +</​code>​
 +
 +===== 何行あるか分からないときのデータファイルの読み込み =====
 +
 +データファイルの中に何行あるか分からないときにはiostatかendを使う.
 +iostatの方がスマートなやり方かも.
 +
 +==== やり方その1 ====
 +read文にiostatのオプションを付ける.
 +iostatが正の数を返す場合はエラー,負の値を返す場合は行の終わりを意味するらしい.
 +<code fortran>
 +program hoge
 +  implicit none
 +  real a,b
 +  integer i,​inputstatus
 +  do i=1,10
 +     ​read(*,​*,​iostat=inputstatus) a,b
 +     ​if(inputstatus>​0) stop "​error"​
 +     ​if(inputstatus<​0) exit
 +     ​write(*,​*) a,b,a**2-b
 +  end do
 +end program hoge
 +</​code>​
 +==== やり方その2 ====
 +
 +endを使う.
 +
 +以下サンプル.プログラムの中では10回ループを回すが,読み込むのは5行分だけ.
 +
 +<code bash>
 +gfortran hoge.f90
 +./a.out < hoge.dat
 +</​code>​
 +
 +hoge.f90
 +<code fortran>
 +program hoge
 +  do i=1,10
 +     ​read(*,​*,​end=999) a,b
 +     ​write(*,​*) a**2-b
 +  end do
 +999 continue
 +end program hoge
 +</​code>​
 +
 +hoge.dat
 +<​code>​
 +1. 1.
 +2. 4.
 +3. 9.
 +4. 16.
 +5. 25.
 +</​code>​
 +
 +===== NaNの検出 =====
 +
 +
 +浮動小数点演算例外を検出するコンパイラオプションがあるので、それを使用する。 ​
 +
 +===== Makefile =====
 +保存するためのmakefile
 +<code bash>
 +DATE=  `date +%y%m%d%H%M`
 +TAR = backup/​backup${DATE}.tgz
 +backup :
 +     tar czvf ${TAR} Makefile *.f90
 +</​code>​
 +
 +
 +===== implicit none =====
 +宣言文で宣言した変数以外を利用しないようにする。
 +長いプログラムを書く場合はミスを避けるためにも使用するべき。
 +自由形式の場合はuse文の後に使用。
 +<code fortran>
 +program hoge
 +  use hoge_lib
 +  implicit none
 +  real(8) a,b,c,
 +  ...
 +</​code>​
 +===== 装置番号 =====
 +write(?,​*)やread(?,​*)の?​に入る番号。
 +通常、5が標準入力(キーボード)、6が標準出力(ディスプレイ上の端末)に使用されるので、
 +5と6を使ってopenするのは避けるべき。
 +slatecのI1MACHを使えば、標準入力、標準出力の番号が調べられる。
 +装置番号にはcharacterも入る。
 +
 +
 +
 +===== 連番のファイル名をつける。 =====
 +ファイル名をcharacter変数に代入して使う。ファイル名の変更にはwrite文を使う。
 +逐次計算に使える。
 +<code fortran>
 +character(len=12) filename
 +...
 +do i=1,100
 +  write(filename,'​(a,​i4.4,​a)'​) '​hoge',​i,'​.dat'​
 +  open(10,​file=filename)
 +  ...
 +    write(10,*) ...
 +  ...
 +  close(10)
 +end do
 +</​code>​
 +
 +
 +
 +===== 簡単なシェルスクリプト =====
 +連続してプログラムを実行したいとき、shファイルが便利。
 +端末で入力する内容をあらかじめファイルに書いておき、それを実行すれば、上から順に実行してくれる。
 +windowsで言うバッチファイル。
 +
 +<code bash>
 +gfortran hoge.f90
 +cd case10
 +../a.out
 +cd ../case20
 +../a.out
 +cd ../case30
 +../a.out
 +</​code>​
 +<​code>​
 +$ sh hoge.sh
 +</​code>​
fortran/tips.1387704495.txt.gz · 最終更新: 2017/10/03 12:55 (外部編集)