Modern Fortran のコンパイルとデバッグ

Windows 10 Pro の WSL2 の Ubuntu18.04LTSで，Intel Fortran (**ifort**) version 19.1.2.275，gfortran 7.5.0 (**gfortran**)，および NAG Fortran 7.0 (**nagfor**) を使用し，沿岸海洋環境数値モデルコードのコンパイルで出会った Warning や Error と対応方針の備忘録です．Libraryは用いず，Fortranソースコードのみからなるプログラムを想定しています．NetCDFを用いて検証したかったのですが，コンパイラ毎に Library を用意するのは大変なので，NetCDFへのリンクの有無をプリプロセッサで制御できるようにし，本記事では外して検証しています．なお，本記事はあくまで個人で開発しているシリアル（並列化されていない）のプログラムを用いた実験結果で，一般性はあまりありません．
bashの環境変数の PATH 設定は **full path** とします（make で見つけられないため）．
結論として，NAG Fortran のコンパイラは未定義（初期化忘れ等）の発見が秀逸で，デバッグに最も威力を発揮しました．
Makefileは以下の様なものを準備しました．

```bash
.SUFFIXES : .o .f90

#FLAG_1 = -DNETCDF_OUT

FC = ifort
#FC = gfortran
#FC = nagfor

CPP = icc -E
CPPFLAGS = -P -traditional
CPPARGS = $(CPPFLAGS) $(FLAG_1)

### Intel Fortran 
FFLAGS = -auto -heap-arrays -ftrapuv -check all -warn -stand -fpe0 -traceback -g
#FFLAGS = -O2 -fp-model precise

### gfortran
#FFLAGS = -fbounds-check -O -Wuninitialized -fbacktrace

### NAG Fortran
#FFLAGS = -C=undefined -w=unused

TARGET = teem.exe

.f90.o :
	$(FC) $(FFLAGS) -c $<

OBJS = mod_util.o mod_globals.o mod_interface.o mod_grid.o mod_grid_bed.o mod_output.o mod_temperature.o mod_salinity.o mod_velocity.o mod_eco_water_param.o mod_eco_bed_param.o mod_eco_flux_param.o teem_flux.o teem_water.o teem_bed.o teem_wavehindcast.o  teem_main.o matrix_solver.o matrix_solver_bed.o bcond_surface_stress.o bcond_discharge.o bcond_bed_stress.o bcond_tide.o scalar_common.o teem_flow.o heat_flux.o coriolis.o etc.o bcond_met.o vdiffusion.o hdiffusion.o turbulence_model.o

#LDFLAGS = "${HOME}/local/netcdf4-intel-fortran/4.5.3/lib"
#INCLUDES = "${HOME}/local/netcdf4-intel-fortran/4.5.3/include"
#LIBS = -lnetcdff

LDFLAGS =
INCLUDES =
LIBS =

.F.o :
	$(CPP) $(CPPARGS) $*.F > $*.f90
#	$(FC) $(FFLAGS) -I$(INCLUDES) -c $*.f90
	$(FC) $(FFLAGS) -c $*.f90
#	rm -f *.f90

$(TARGET) : $(OBJS)
#	$(FC) -o $@ $(OBJS) -L$(LDFLAGS) $(LIBS)
	$(FC) -o $@ $(OBJS) $(LIBS)

run :
	./$(TARGET) <./input/in2000m1999_1.dat

clean :
	rm -f $(OBJS) $(TARGET) *.mod *.f90

```


# [Intel Fortran](https://www.xlsoft.com/jp/products/intel/download/doc.html) (ifort)

### オプション選択と計算結果への影響
標準的なオプションとして以下を採用しています．テストに用いたコードでは `-O2`
と `-O3` の差はないようでした．

```bash
FFLAGS = -O2 -fp-model precise  # 標準
FFLAGS = -O2 -fp-model precise -traceback  # 実行時エラー情報取得
FFLAGS = -auto -ftrapuv -check all -warn -stand -traceback  # デバッグ時
FFLAGS = -auto -ftrapuv -check all -warn -stand -traceback -g  # デバッグ時 debugger利用
```

コンパイルオプションの異なる2つの実行形式を用意し，計算結果の実数配列値の差の絶対値の和をとり，チェックしたところ，以下の様になりました．

```bash
-O2 VS -O3  # No difference
-O2 VS -O2 -fp-model precise  # Significant difference
-O2 -fp-model precise VS -O2 -fp-model precise -fpe0  # No difference
-O2 -fp-model precise VS -O2 -fp-model precise -fpe0 -traceback  # No difference
-O2 -fp-model precise VS -O2 -fp-model precise -fpe0 -traceback -xHost  # Significant difference
```

結論として，`-fp-model precise` の有無と `-xHost` の有無が結果に大きく影響しました．テストケースは1年分の境界条件を用意し，沿岸海洋環境の変動を時々刻々再現するもので，同一の境界条件を用いて複数年の計算を実施し，平衡解（に近いもの）を得ようとするものです．1年程度の計算ではオプションによる差は軽微ですがが，10年分計算すると結構変わります．

### Warning への対応

##### forrtl: warning (406): fort: (1): In call to MYFUNC, an array temporary was created for argument #1 [**参考**](https://community.intel.com/t5/Intel-Fortran-Compiler/An-array-temporary-was-created-for-argument-x/m-p/1186619?profile.language=ja)
実引数 Array(1,1:10) を仮引数 Dummy(1:10) で受け取る場合はtemporary arrayが作成され，性能が劣化するようです．実引数の配列のメモリアクセスが不連続なためです．

##### Warning #5268: Extension to standard: The text exceeds right hand column allowed on the line.
1行132桁以内とする

##### Warning #8889: Explicit declaration of the external attribute is required
外部プロシージャのインターフェースを用意することで対応します．

### デバッガー gdb
コンパイルオプション `-g` を追加してコンパイルを実行し，実行形式が `teem.exe`，標準入力に与えるファイルが `./input/in.dat` とします．デバッガを実行すると詳細なエラー情報が表示されるはずです．

```bash
$ gdb teem.exe  # gdb 実行形式
(gdb) run <./input/in.dat  # run [< 標準入力用のファイル]
```

抜けるには `quit` と入力します．

#### Tips
NAG Fortran のおかげで変数の値が未定義のエラーがなくなった後で，ifort で `-auto` を追加してコンパイル・実行すると（-auto以外のオプションでは問題なく実行できていました），`forrtl: severe (174): SIGSEGV, segmentation fault occurred`となりました．デバッガで調べたところ，以下のようなエラーでした．

```bash
Program received signal SIGSEGV, Segmentation fault.
0x00000000004ebe27 in teem_ecosystem_water::teem_eco_water_run (
    lout3d=<error reading variable: Cannot access memory at address 0xcccccccccccccccc>,
    tempt=<error reading variable: value requires 166320 bytes, which is more than max-value-size>,
```

スタック領域の不足を疑い，`$ ulimit -s unlimited` としたところ，問題なく実行できました．一方，コンパイルオプションの `-heap-arrays` を加えてコンパイルしても，このエラーは解消されませんでした．

# [NAG Fortran](https://www.nag-j.co.jp/nagfor/np70_manual/compiler.html) (nagfor)
トライアルではじめて利用させていただきました．[**強力なプログラムチェック機能**](https://www.nag-j.co.jp/nagfor/) が売りとのことでしたが，それを実感し，感動しました．

### オプション選択と計算結果への影響
NAG Fortran は未定義（初期値設定忘れ）の変数を発見する性能が秀逸です．デバッガーなしで実行時に問題箇所を指摘してくれました．配列の一部の値の指定漏れを指摘したのは NAG Fortran だけでした．

```bash
FFLAGS = -C=undefined -w=unused  # デバッグ時
```

### Warning への対応
##### Questionable: ###.f90, line ###: DO index variable ### is not a local variable (it is from module ###)
module procedure内のDOループ変数を（行数節約のため）module変数として定義した場合に現れます．素直に各procedure内で局所変数として定義するのがよいでしょう．


### その他
**Fortran Builder** をWindowsにインストール後，WSL2-Ubuntu の bashターミナルを立ち上げるとsyntaxエラーが発生しました．原因はWindowsのPATHが自動的に取り込まれる際，(x86)のように括弧を含むPATHを解釈できないためでした．Fortran Builderのデフォルトのインストール先は(x86)を含むフォルダ名で，これを適切に変更すれば回避できます．また，Fortran Builder の nagfor.exe を WSL2 の Ubuntuで使えないか試しましたがうまくいきませんでした．本記事はLinux版を使用しました．

# [The GNU Fortran](https://gcc.gnu.org/onlinedocs/gfortran/) (gfortran)
NAG Fortran を使用する前にgfortranを使ってみました．Intel Fortranよりも未定義変数を見つける性能が優れていると感じました．

```bash
FFLAGS = -fbounds-check -O -Wuninitialized -fbacktrace
```

# 参考資料
- Metcalf, M., Reid, J. and Cohen, M. *Modern Fortran explained*, Oxford University Press, 2018.
- Markus, A. *Modern Fortran in Practice*, Cambridge University Press, 2012.
- Brainerd, W. S. *Guide to Fortran 2008 Programming*, 2nd edition, Springer, 2015.
- Curcic M. *Modern Fortran - Building efficient parallel applications -*, Manning, 2020.
- Chirila, D. B. and Lohmann, G. *Introduction to Modern Fortran for the Earth System Sciences*, Springer, 2015.
- 牛島省．数値計算のためのFortran90/95プログラミング入門（第2版），森北出版，2020．
- 暗黙の型宣言編著．Fortranによる実践オブジェクト指向プログラミング，2018．
- [NAG Fortran コンパイラ 7.0 マニュアル](https://www.nag-j.co.jp/nagfor/np70_manual/compiler.html)
- [Damian Rouson](https://www.lanl.gov/conferences/salishan/salishan2014/rouson.pdf) This is not Your Parents' Fortran: A scalable, Parallel, Functional, OO PDE Solver
- [Wikipedia](https://en.wikipedia.org/wiki/Partitioned_global_address_space): Partitioned global address space (PGAS) ([和訳](https://www.deepl.com/translator#en/ja/In%20computer%20science%2C%20a%20partitioned%20global%20address%20space%20(PGAS)%20is%20a%20parallel%20programming%20model.%20It%20assumes%20a%20global%20memory%20address%20space%20that%20is%20logically%20partitioned%20and%20a%20portion%20of%20it%20is%20local%20to%20each%20process%2C%20thread%2C%20or%20processing%20element.%5B1%5D%20The%20novelty%20of%20PGAS%20is%20that%20the%20portions%20of%20the%20shared%20memory%20space%20may%20have%20an%20affinity%20for%20a%20particular%20process%2C%20thereby%20exploiting%20locality%20of%20reference.%20The%20PGAS%20model%20is%20the%20basis%20of%20Coarray%20Fortran%2C%20Unified%20Parallel%20C%2C%20Split-C%2C%20Fortress%2C%20Chapel%2C%20X10%2C%20UPC%2B%2B%2C%20Coarray%20C%2B%2B%2C%20Global%20Arrays%2C%20DASH%20and%20SHMEM.%20In%20standard%20Fortran%2C%20this%20model%20is%20now%20an%20integrated%20part%20of%20the%20language%20(as%20of%20Fortran%202008).%20PGAS%20attempts%20to%20combine%20the%20advantages%20of%20a%20SPMD%20programming%20style%20for%20distributed%20memory%20systems%20(as%20employed%20by%20MPI)%20with%20the%20data%20referencing%20semantics%20of%20shared%20memory%20systems.%20This%20is%20more%20realistic%20than%20the%20traditional%20shared%20memory%20approach%20of%20one%20flat%20address%20space%2C%20because%20hardware-specific%20data%20locality%20can%20be%20modeled%20in%20the%20partitioning%20of%20the%20address%20space.%0A%0AA%20variant%20of%20the%20PGAS%20model%2C%20asynchronous%20partitioned%20global%20address%20space%20(APGAS)%20permits%20both%20local%20and%20remote%20asynchronous%20task%20creation.%5B2%5D%20Two%20programming%20languages%20that%20use%20this%20model%20are%20Chapel%20and%20X10. www.DeepL.com/Translator（無料版）で翻訳しました。))