モダンFortran勉強会.f01で出た話題

# 概要
[モダンFortran勉強会.f01](https://modern-fortran-local-user-group.connpass.com/event/128783/)で出た話題のうち，プログラミング言語のテクニックや仕様に関わる話題を，走り書きですが記憶が新鮮なうちにまとめました．
ご意見頂ければ修正・加筆していきます．

# 情報交換
## デバッグ方法について
本番環境がIntelだがVisual Studioがない．デバッグはどうすればいいか？よいデバッガはあるか？
（以下，最初の話題からトップギアに入る参加者達）

- gfortranでコンパイルし直してgdbを使うのがよい
    - Intelは独自拡張があるので，gfortranでコンパイルするときに色々エラーが出る
        - 論理型の比較には`.eqv.`, `.neqv.`を使おう（Intelは==が使える）
        - write/print文での整数型の書式指定には`i0`を使おう（Intelは`i`と書いて同じ事ができる）
        - stdオプションを付けて規格に準拠していない構文をチェックする意識を持った方がよい
            - [Intel](https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-stand)   /stand {f90|f95|f03|f08|f18}
            - [gnu](https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html)   -std={f95|f2003|f2008|f2018|gnu|legacy}
                - stdがたまにバグるという情報もあり
            - [PGI](https://www.pgroup.com/resources/docs/17.10/pdf/pgi17ref-x86.pdf)   -Mstandard
        - FRT（FujitsuのFortranコンパイラ）はそのあたり優秀
        - NECのSX-Aurora向けのコンパイラは，言語仕様に沿ってきっちり作ったのに「俺のコードがコンパイルできない」と苦情が来るという話を展示会で聞いた
- デバッガを使えるようになるのも長い道のり
    - ブレイクポイント，ステップ実行など，デバッガのコマンドへの習熟
    - モジュール内変数の参照の仕方など
        - hoge::fuga（C++のnamespaceと同じ）
    - print文を書いたり消したりするのと，どっちが手間がかかるんだろう

- GUIでやるなら
    - Eclipse
        - Eclipseへのインテルデバッガの統合という記事もあるが，現在有効かは不明
        - EclipseにはPhotranというFortran向けプラグインがある
    - [Code::Blocks for Fortran](http://www.codeblocks.org/)
        - [Code::Blocks IDE for Fortran](http://cbfortran.sourceforge.net/)
        - [Debugging Fortran code in the Code::Blocks IDE](http://cbfortran.sourceforge.net/debugging/)
        - [Fortranの開発環境をWindowsで構築したときのメモ](https://ignisan.hatenablog.com/entry/20110501/1304250630)

- Fortranの用途に応じた出力をしたい
    - Fortranの用途は物理シミュレーション
    - 大きい配列を使うので，デバッガを使っても全部確認しきれない
        - 結局ファイル→可視化
        - Pythonと連携して，可視化結果を画像で吐き出す方法もある
    - 配列の中身をGUIで確認したい
        - [Nsight Visual Studio Edition Graphics Debugger](https://developer.nvidia.com/nsight-visual-studio-edition)みたいな感じ

- Fortranは統合開発環境が弱い
    - Fortranは文法に難があり，IDEの開発が難しい
        - 文関数←とくにこいつ
            - COBOLのように，ここまでが宣言文，ここからが実行文と明記するなら，まだやりようがある
        - C++も大概難しいが，使う人が多いので頑張って作られている
        - Fortranは･･･
    - Fortranは仕様が色々と遅れている
        - プリミティブな数値型に独自拡張が溢れているのに，`int32`とかのパラメータを定義する前にOOPを導入するとか順番が違うでしょ

- documentationツール
    - Doxygen
        - リリース用のドキュメントを作るには向いている
        - 差分だけを作り直す機能がなくて，時間がかかる
            - Continuous Integrationには向かない
        - 関数をオーバーロードすると上手くいかない
    - 話題提供のところでFORDというdocumentationツールが紹介される→継続調査

- みんなでコーディングスタイルを作ろう！

### 使っているコンパイラ
|ベンダ|人数|
|:--|:--|
|Intel|ほぼ全員|
|gfortran|ほぼ全員|
|pgi|若干名|
|Fujitsu|若干名|
|NEC|若干名|
|NAG|若干名|
NAG結構いいよとのコメントあり．

## FORTRAN MODERNIZATION WORKSHOP
Fortran Modernization Workshopの紹介があった．

- NAG が主催
- TU Dortmund, 20 February 2019
- University of Manchester, 4-5 April 2019
- Universität Basel, 26-27 June 2019←次回
[Workshop紹介ページ](https://www.nag.co.uk/content/fortran-modernization-workshop)に資料の一部がある．

- 日本でもやって欲しいが，どこに声をかければよい？
- 予定を超過するぐらいの人気イベント．日本だけじゃなくて海外もFortran事情は同じ．

# 話題提供
## スペクトル法をモダンFortranで実装すること
- スペクトル法では，物理空間で定義された物理量を波数空間に変換し，そこで微分を計算する．
$$
    u = \sum_{k=-\frac{N}{2}}^{\frac{N}{2}-1} \hat u_k e^{ikx}
$$
- 計算のほとんどはFFT
- $u$をFFTして$ik$かけて逆FFTをやると微分が計算できる
- $u$は実数なので，複素共役$\hat u_{-k}^*=\hat u_{k}$となる

物理空間（全部実数）→FFT（全部虚数）→微分→逆FFT（全部実数）なので，`complex`を使うが，`equivalence`でメモリの節約を図っている．

```Fortran
real(real64) :: u(Nx,Ny,Nz)
complex(real64) :: uk(Nx/2,Ny,Nz)
equivalence(u,uk)
```

- `equivalence`は廃止事項なので，代替手段はあるか？
- 多くのFFTライブラリはクラシックなもので引数の制約がある

- 会場からの意見
    - FFTWは？使いこなすのが大変
    - 京大の石岡先生 ISPACKはどう？
    - Cのポインタ(`type(c_ptr)`)を噛ませばいけるにはいけるが，最適化が途絶えてしまう
    - バグ技みたいな方法で，realを渡してcomplexで受け取れば行けそうだが，できたとしてもやらない方がよい

- equivalenceにまつわるネット上での議論（2019年5月7日追記）
    - [アンケート結果に対する回答 ＜並列Fortranシンポジウム(2015/8/18)＞](http://site.hpfpc.org/home/events/parallel_fortran_sympo/answers)
        - 廃止予定事項だから本当に廃止されるのは先
        - `aimag`や`%im`を使いましょう
        - 複素数配列を引数で渡して倍の長さの実数配列で受けることもできるんじゃないかな･･･？
    - [Modernizing Old Fortran](http://fortranwiki.org/fortran/show/Modernizing+Old+Fortran)
        - EQUIVALENCE Statementに記述はあるが解決策は無し
    - [equivalence discussion](http://fortranwiki.org/fortran/show/equivalence+discussion)
        - 同様の事をする手段は，`transfer`，Cray pointer，Cのポインタがある．
    - [Better support for EQUIVALENCE](http://fortranwiki.org/fortran/show/Better+support+for+EQUIVALENCE)
        - グローバル変数，gotoと同じく，用法・用量を守って正しくお使いください
        - `transfer`を使う．効率的なコンパイラは不要なコピーを認識して，in-placeでデータを使えるはず
        - 廃止予定事項には触れず

### Fortranでのデザインパターン(GoF)
- 最終的には設計の問題に行き着く．Fortranでデザインパターンは使えるのか？

- 会場からの意見
    - Strategy，Template，Factoryパターンはそのまま使える
    - Singletonパターンはちょっと工夫が要る．
        - protectedを使えばいける
        - 局所的にポインタの利用を強制することになる
    - Iteratorパターンは結構苦しい
        - 結局，基本的な設計がOOPよりになっていない．静的な言語でやろうとしている限界
    - GoFのデザインパターンはJavaの表現力を補うためのもの．Fortranに適したパターンはFortranユーザが考える
        - Rouson, Xia, Xu, Scientific Software Design: The Object-Oriented Way, Cambridge University Press(2011).
            - Surrogateパターン，Puppeteerパターンとか

### fortran77のプログラムを書き換えるうまい戦略
- Fortran77のプログラムが多くある
- implicit noneも付いてない
- バグがあるような状況で，動作を確認しつつ新しい形に書き換えたい
- そういう時にどういう手順でやるか？特に**経験の長い人を説得する方法**

- 会場からの意見
    - 内部副プログラムやBlock構文で局所的に変更する
    - ラッパーを書いて見た目だけきれいにして，中から古いのを呼ぶ
    - 一般的に難しい問題
        - 古いコードを消したり，implicit noneを浸透させたりするのに年単位でかかったという経験談
        - コミュニケーションコストがかかる
        - 労力をかけてやるべき事かどうか
        - FORTRANの問題と思われがちだが，結局は組織の問題に帰着する

### 数値計算に利用すべき機能，利用すべきでない機能
- 数値計算に有用な機能に何がありますか？
- PyFRというオープンソース圧縮性NSソルバーがある
    - Fortranでなくてもよい？何の機能があればFortranを使う？

- 会場からの意見
    - maxvalとか一括代入のような配列に対する処理
    - pure, elementalな関数
        - これができる言語は少ない
        - numpy.vectorizeはforを呼ぶので遅い
    - Pythonでゴリゴリチューニングすると，可読性が落ちる
        - この処理はPythonでどう書こう？と考えた時点でPythonで書くべきではない
    - アルゴリズム的な処理を考えて，最速を狙うならうまくライブラリを使う
        - 行列演算はlapackを使う

## 発表
### FortranからPythonを呼ぶ
- Pythonを使い，高速化のためにFortranの関数をPythonから呼ぶという記事が多い．
- 逆に，FortranからPythonの機能を呼ぶことで，Fortranが苦手にしていることを解決できる
    - 特に文字列処理．引数にundocumentedな順番があったりする
- Python
    - Cython
    - numpy
    - ctypes
- Fortran
    - iso_c_binding

- [サンプルプログラム](https://github.com/ijknabla/fortran-call-matplotlib)
    - Mandelbrot集合
        - matplotlibをFortranから呼ぶ
        - コマンドライン引数はargparseを利用
            - utf-8を引数で受け取っている

- 任意のPythonのオブジェクトをcharacter(:),allocatableで持たせられる．

### forpyの調査
- FortranにPythonを埋め込む
    - ~~資料は近いうちに公開します．~~
    - [資料](https://note.mu/mmer547/n/n8744d798d5bc)（2019年5月9日追記）
- [forpy - Github](https://ylikx.github.io/forpy/index.html)
- [FORD](http://fortranwiki.org/fortran/show/FORD)
    - Forpyに対応したdocumentation tool
    - > Ford was written due to Doxygen’s poor handling of Fortran and the lack of comparable alternatives.

    という期待の高まる1文が．


### FortranをPythonに近づけろ～fortran-utilsを使ってみた～
- [資料](https://gitpitch.com/tkoyama010/modernfortran-tkoyama010/modernfortran.f01#/)
- 前二つは，PythonをFortranから呼ぶ方法
- これはあくまでFortranを全部使ってPythonに近づける
- なぜその言語を使うのか？→ライブラリが使えるから
    - Python単体でできることは多くない
    - numpy/scipyがあるから使われている
- [fortran-utils - Github](https://github.com/certik/fortran-utils)
    - 作者はsympyのcontributor
    - numpy/scipyの書き方を再現できている
    - 特殊関数でセグフォが起こったので，修正している
        - [forkした修正版](https://github.com/tkoyama010/fortran-utils)
        - もう開発していないみたいなので，プルリク送ってもマージされなさそう
    - constantsモジュールに$\pi$, $e$, $i$が定数として定義されている（2019年5月6日追記）
        - Fortranはなぜ$\pi$すら定数として用意されていないのか？

### なぜ文字列と文字型配列を混同してしまうのか
- [資料](https://www.slideshare.net/ssuserf87701/why-do-we-confuse-string-and-array-of-characters-in-fortran)
- 混同する理由
    - 文字の配列・文字列の区別がついていない
    - 仮引数の書き方がややこしい
    - 型チェックが効かない場合がある
- 対策
    - 文字列は`character(:),allocatable :: str`で宣言して，関数で受け取るときは`character(*) :: str`とする
    - 文字の配列は`character,allocatable :: char(:)`で宣言して，関数で受け取るときは`character :: char(:)`とする