超音波流体屋のプログラム備忘録
Fortran
最終更新:
usapfrog
-
view
Matlabが遅いよってことで一から勉強するよ
Hello Worldまで
コンパイラだけなら、linuxは常備(なかったらyumなどで)。
[Windows]
OctaveかMingGW環境で手に入る。
Windowsならインストール後"C:\Octave\Octave3.6.4_gcc4.6.2\mingw\bin"と"C:\Octave\Octave3.6.4_gcc4.6.2\mingw\msys\1.0\bin"
または、"C:\MinGW\bin"と"C:\MinGW\msys\1.0\bin"にパスを通しとくのを忘れないこと。
(LAPACKを使う予定があるならOctaveをいれておくこと)
[Windows]
OctaveかMingGW環境で手に入る。
Windowsならインストール後"C:\Octave\Octave3.6.4_gcc4.6.2\mingw\bin"と"C:\Octave\Octave3.6.4_gcc4.6.2\mingw\msys\1.0\bin"
または、"C:\MinGW\bin"と"C:\MinGW\msys\1.0\bin"にパスを通しとくのを忘れないこと。
(LAPACKを使う予定があるならOctaveをいれておくこと)
[Mac]
macportsやhomebrewなどで、gfortranをインストールする。
macportsやhomebrewなどで、gfortranをインストールする。
$ vi test.f90 program main write(*,*)'Hello World' end $ gfortran test.f90 $ a.exe
開発環境/IDE
まあでも、やっぱIDE欲しいよ。
(WindowsならMinGW導入後) EclipseのPhotranを導入する。
導入法に従って、インストール。
(今までのeclipseに後付しないんなら Eclipse for Parallel Application Developersを落としてきて解凍すればよし)
(WindowsならMinGW導入後) EclipseのPhotranを導入する。
導入法に従って、インストール。
(今までのeclipseに後付しないんなら Eclipse for Parallel Application Developersを落としてきて解凍すればよし)
ついでに日本語化をしておく。
- http://mergedoc.sourceforge.jp/の真ん中下くらいのPleiades プラグインをダウンロード・解凍
- 中身をeclipseのフォルダにコピペ・統合する。
- eclipse.iniの最終行に以下を追加
-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
- 初回のみ同梱のeclipse.exe -clean.cmdから起動する
- 64bit windowsで起動時にJavaがエラーがないとエラーが出るときは、64bit javaを手動でインストールして、http://www.java.com/ja/download/manual.jsp、C:\Program Files\Java\jre7\binにパスを通すこと
- 新規→プロジェクトでFortranぽいのを選ぶ
- 新規→ソースでFortranソースを選ぶ
- 上のプログラム書く
- ビルド・実行 (合間にでるオプションは Local Fortran Application, MinGW gdb)
参考
(pdf)eclipseでFortranプログラムの作り方
(pdf)eclipseでFortranプログラムの作り方
コード規約
変数宣言
変数同士の計算式は大体C同様で計算できる。
複素数標準実装、倍精度のdの使い方が特徴的。
というよか、Fortranでは少し神経質に倍精度指定しなきゃならないらしい。
うっかり1.0とか使うと、単精度になり桁に余計なゴミが入る。
複素数標準実装、倍精度のdの使い方が特徴的。
というよか、Fortranでは少し神経質に倍精度指定しなきゃならないらしい。
うっかり1.0とか使うと、単精度になり桁に余計なゴミが入る。
- program sample
- integer :: a
- logical :: p
- real(8) :: y
- complex(8) :: s
- character(len=4):: w
-
- a = 3
- p = .true.
- y = 42.0d0 !dは 3e-3のeみたいに使う
- s = (6.0d0, 3.0d0) !これで s = 6 + 3i
- w = "abcd"
-
- print *, a, z, u, w
- end program sample
-
追記: characterはcharcter :: w*4でなく上記フォーマットのほうが了解性の点で良いらしい。
掛け算と混同してもいかんしね。
掛け算と混同してもいかんしね。
配列
足し算・内積。行数がずいぶん削れるのがありがたい。
printの書式はCとちょっと違う感じ。
printの書式はCとちょっと違う感じ。
- program sample
- implicit none
-
- integer, parameter :: D = 3
- real(8) :: x(D) = (/1d0, 2d0, 3d0/)
- real(8) :: y(D) = (/2d0, 1d0, -1d0/)
- real(8) :: z(D), v(D)
- real(8) :: w
-
- real(8) :: A(D,D)
- A(1,1:3) = (/ 8.0d0, 1.0d0, 6.0d0 /)
- A(2,1:3) = (/ 3.0d0, 5.0d0, 7.0d0 /)
- A(3,1:3) = (/ 4.0d0, 9.0d0, 2.0d0 /)
-
- z(:) = x(:) + y(:)
- v = matmul(A, x)
- w = dot_product(x, y)
-
- print "(a, f8.3, f8.3, f8.3)", "z=", z
- print "(a, f8.3, f8.3, f8.3)", "v=", v
- print "(a, f8.3)", "w=", w
- end program sample
-
結果
z= 3.000 3.000 2.000 v= 28.000 34.000 28.000 w= 1.000
ループ・分岐
do i=初期,限界,増分
else if (condition) then
else if (condition) then
結果
loop i= 1 loop i= 2 loop i= 3 loop i= 4 loop i= 5 loop i= 6 exiting loop... 4 18
関数・モジュール
追記:引数には入出力指定を示すintent(in/out/inout)を付記すること。
sampmodule.f90
- module sampmodule
- implicit none
- real(8),parameter :: c = 340d0
- real(8),parameter :: rho = 1.3d0
- contains
- integer function smd_test(a, b, x)
- integer, intent(in) :: a, b, x
- smd_test = a + b * x
- end function smd_test
- real(8) function smd_pres(u)
- real(8), intent(in) :: u
- smd_pres = rho * c * u
- end function smd_pres
- end module sampmodule
-
sample.f90
- program sample
- use sampmodule
- implicit none
- integer :: d
- real(8) :: p
- print *,c
- d = smd_test(1, 3, 5)
- print *,d
- p = smd_pres(2.0d0)
- print *,p
- end program sample
-
ベクトルを返すとき
戻り値がベクトルの時は、resultを指定する。例は外積関数。
- function cross(a,b) result(axb)
- implicit none
- real(8),dimension(3) :: axb
- real(8),dimension(3),intent(in) :: a
- real(8),dimension(3),intent(in) :: b
-
- axb(1) = a(2)*b(3) - a(3)*b(2)
- axb(2) = a(3)*b(1) - a(1)*b(3)
- axb(3) = a(1)*b(2) - a(2)*b(1)
- end function cross
-
テキストIO
statusのオプションが "r/w"に対応して、"old / (new, replace)"
追記をしたいときはopen文にposition='append'オプションを付ける。
エラー処理をしたければiostat=status(整数変数)をつければ、
open時読み込みエラーをstatusに格納してくれて、open時のエラーをスルーできる。
追記をしたいときはopen文にposition='append'オプションを付ける。
エラー処理をしたければiostat=status(整数変数)をつければ、
open時読み込みエラーをstatusに格納してくれて、open時のエラーをスルーできる。
- program sample
- implicit none
- integer :: i, j, status
- integer,parameter :: fout = 11
- integer,parameter :: fin = 12
- real(8) :: x(20,20)
- do i=1,20
- do j=1,20
- x(i, j) = i * 100d0 + j;
- enddo
- enddo
- write(fout, *) x
- close(fout)
- if ( status .ne. 0 ) stop
- read(fin, *) x
- close(fin)
- end program sample
-
バイナリIO
サイズを指定して、オプションが長くなるだけ。 access, form, recl, rec
- program sample
- integer :: siz = 20*20*8
- read(fin, rec=1) x
- close(fin)
- write(fout,rec=1) x
- close(fout)
- end program sample
-
共有メモリメモリ並列(SMP)
gfortranの共有メモリ並列(-fopenmp)はコンパイラオプションの最適化(-O3)とどこか相性悪いらしく、
扱う配列サイズがやや大きい場合、segmentaion faultを吐くことがあるらしい。
この場合、最適化は(-O1)を指定するとうまくいくことがある。
扱う配列サイズがやや大きい場合、segmentaion faultを吐くことがあるらしい。
この場合、最適化は(-O1)を指定するとうまくいくことがある。
バグった時はprivate指定をもう一度見なおしておくと良い。
3次逆行列/3次方程式
N>4のときは、素直にLapackとか然るべき数値計算ルーチンを使うべきだけど、
多用する3x3くらいは、(必要なライブラリかき集めるのめんどいし、四角い車輪の再生産にあるけど)
自分で書いていい気がする。
多用する3x3くらいは、(必要なライブラリかき集めるのめんどいし、四角い車輪の再生産にあるけど)
自分で書いていい気がする。
- function inv3(A) result(Y)
- implicit none
- real(8), intent(in) :: A(3,3)
- real(8) :: Y(3,3)
- real(8) :: det
- integer :: i,j
- det = 0
- do i=1,3
- det = det + A(i,1)*cofact3(A,i,1)
- end do
- do i=1,3
- do j=1,3
- Y(i,j) = cofact3(A,j,i) / det
- end do
- end do
- end function inv3
- real(8) function cofact3(A,i,j)
- implicit none
- real(8), intent(in) :: A(3,3)
- integer, intent(in) :: i, j
- integer :: i2, i3, j2, j3
- i2 = mod(i, 3)+1; i3 = mod(i+1, 3)+1;
- j2 = mod(j, 3)+1; j3 = mod(j+1, 3)+1;
- cofact3 = A(i2,j2)*A(i3,j3)-A(i2,j3)*A(i3,j2)
- end function cofact3
-
- !wikipediaの三次方程式の解の公式・実部しか取ってこないので注意
- subroutine solve3(x, a)
- implicit none
- real(8), intent(out) :: x(NDIM)
- real(8), intent(in) :: a(NDIM)
- integer :: k
- complex(8) :: j, w, y(NDIM), p, q, R, S
- j = (0, 1)
- p = a(2)-a(1)**2/3d0
- q = a(3)-a(2)*a(1)/3d0+2d0/27d0*a(1)**3
- do k=1,3
- y(k) = w**(k-1) * R + w**(4-k) * S
- x(k) = real(y(k),8) - a(3)/3d0
- end do
- end subroutine solve3
-