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