Emacsに関する話. Fortran advent calendar 23日目
Fortran(やその他)のコードを素早く試したい方向け.
ソースコードはこれのorg-babel_and_Fortran.org.
https://github.com/osada-yum/examples
- 実行環境
- Emacs26.3 on Ubuntu20.04 on VirtualBox 6.1.14
- Emacs28.0.50 on Ubuntu20.04
- Org mode version 9.1.9
Org mode
Emacsの文書作成モード, 他のエディタでも使える. MarkdownみたいにhtmlやLaTeXファイルを生成することもできる. Emacs26.3ではインストールなしで使える?
Org babel
Org modeでコードを実行できるやつ. Emacs26.3ではインストールなしで使える? org-babel-do-load-languagesで読み込む言語を指定. この記事ではこれらを使う. org-src-lang-modesはeditのときのモードを指定できる.
対応言語, M-x package-list-packageでob-*を探せばもっとある. (ob-prologとかob-rustとかob-ess-juliaとか.)
# +BEGIN_src emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(fortran . t)
(R . t)))
# +END_src
コードの実行
参考
Fortranコードブロックの実行
:exportsはhtmlやLaTeXへの変換に使用される. :results outputは#+RESULTが標準出力の内容になる. :cache yesならコードブロックの実行のキャッシュが取られて同じコードブロックの実行をする必要がなくなる.

#+BEGIN_src (language)と#+END_srcで囲む. (大文字でも小文字でも#+BeGin_sRcでもよい.)

C-c C-'で別のウィンドウ(Emacs用語)で編集できる. C-c C-'で終了. C-c C-kで取り消し.

単精度実数と倍精度実数は7桁程度一致していること. acos(-1)でも`4*atan(1)でも15桁程度一致している.
コンパイラの変更
Emacsの変数のorg-babel-fortran-compilerによって決まる. デフォルトでは"gfortran". org-version 9.1.9ではdefvarで宣言されているのでsetqを使って変更する. (9.5ではdefcustomで宣言されているため, M-x customizeで設定できる.)
(setq org-babel-fortran-compiler "ifort")
f90-modeでコードブロックの編集をする.
#+BEGIN_src fortranではC-C C-'を押したときのモードがfortran-modeとなっている. f90-modeにするにはorg-src-lang-modesを変更すればよい.
# +BEGIN_src emacs-lisp
(add-to-list 'org-src-lang-modes '("fortran" . f90))
# +END_src
コンパイラのフラグの指定
拡張子が大文字の.F90なのでプリプロセッサが働くから-cppはあってもなくてもよい.
結果のファイルを覗くと, コードブロック内の内容にprogram main * end programを付けていることが分かる. ファイル名はランダムで決まる. FOOはコンパイラによって置き換えられる. BARは暗黙の型宣言によって単精度浮動小数の未初期化の変数となっている.
# +NAME: flag
# +BEGIN_src fortran :flags '("-cpp" "-DFOO=3") :results output table
print*, __FILE__, __LINE__
print*, FOO, BAR
# +END_src
# +RESULTS: flag
| /tmp/babel-eIDpbc/fortran-src-<random>.F90 | 4 |
| 3 | <uninitialized-variable> |
表の出力の長さの制限を変える
org-table-convert-region-max-linesを変更する. ただ, M-x describe-variable org-table-convert-region-max-linesには大きいとorg-table-convert-regionが遅くなると書いてあるのであまり大きくしてはいけない.
(customize-set-variable 'org-table-convert-region-max-lines 10000)
Fortranでデータを生成してRでプロットしてみる.
:varの後に変数を指定できる. 変数には表も指定できる. fortranのコードブロックでgen_randという名前の表を生成して, Rのコードブロックでgen_randの結果をvalsに代入して, プロットしている.
# +NAME: gen_rand
# +BEGIN_src fortran :var n=1000 :exports results :results output table :cache no
real(8) :: rnd(n)
call random_number(rnd)
print'(i0, a, es20.8)', (i, " ", rnd(i), i = 1, n)
# +END_src
# +NAME: plot_ran_num
# +BEGIN_src R :var vals=gen_rand :exports results :results output graphics :file rand_num_plot.png :cache yes
colnames(vals)[1:2] <- c("iterate", "random")
plot(vals$random)
# +END_src
まとめ
- Org babelでコードブロックを素早く実行できる.
- fortranをコードブロックで使うため,
org-babel-do-load-languagesを使用した. -
f90-modeをコードブロックの編集で使うため,org-src-lang-modesを変更した. - あるコードブロックの結果を別のコードブロックから利用して図を描くことができる.
結論
これはFortranの記事なのだろうか?
まあ, 例えば, Intrinsic Proceduresを見て, adjustlとadjustrとtrimの違いは何か調べたくなっても, 以下のようにしてC-C C-Cで素早く実行できるのはインタプリタではないgfortranにとってはプラスであろう.
(lfortranを使うという手もある上, gfortran prog.f90 && ./a.outで直ぐに実行できるけれども, 文字変更して直ぐにC-c C-cを押す方が速いはず.)
# +BEGIN_src fortran :exports results :results output
character(len=20) :: str = " gfortran "
print'(2a)', "adjustl: ", "|"//adjustl(str) //"|"
print'(2a)', "adjustr: ", "|"//adjustr(str) //"|"
print'(2a)', "trim : ", "|"//trim(str) //"|"
print'(2a)', "| |", "|"//" "//"|"
# +END_src
# +RESULTS:
: adjustl: |gfortran |
: adjustr: | gfortran|
: trim : | gfortran|
: | || |
参考資料
Org mode
Org babel
GFortran

