Fortranの基本ざっくりまとめ

# はじめに
研究で主にJulia, Pythonを使っていたのですが、私がずっと逃げてきたfortranを触る必要が出てきたので、ざっとfortranコードを読めて書くための基本をまとめました。
###### この記事で分かること
- ざっくりとfortranの書き方, 動かし方が分かる
- 変数の型定義
- 配列
- ループ系の文法
- ファイル入出力
- 標準入出力
- 関数の書き方
- サブルーチンの書き方
- モジュールの書き方

# 書き方
基本的には以下の例のようなプログラム構成になります。
例として、1~10の総和を取って標準出力にprintするプログラムを載せました。

```fortran
program main
    implicit none ! 暗黙の変数の型に関する規則(変数の先頭がi~nまでだと整数、それ以外では実数になるという規則)を無効にする

    ! ---------変数定義 ----------------------------------------
    integer :: i
    real(8) :: nums(10)
    real(8) :: total

    ! ---------実行文 ----------------------------------------
    total = 0.d0
    do i = 1, 10
            nums(i) = i
    enddo
    total = sum(nums)

    write(*, *) 'total = ', total ! 他の言語でいうprint文
    ! write(ファイル番号, 書式) 出力対象1, 出力対象2,,,
    ! ファイル番号に* -> 標準出力
    ! 書式に* -> 並び出力(write文の後に並ぶ変数の型にあった書式で出力される)

end program main
```

- implicit none
おまじないなので、必ず書く。
意味としては、暗黙の変数の型に関する規則(変数の先頭がi~nまでだと整数、それ以外では実数になるという規則)を無効にするというものになります。

## プログラム実行方法
fortranはコンパイルしてから実行するので、`gfortran ファイル名.f90`でコンパイルします。
その後、a.outというコンパイルされたファイルが作成されます。
これを実行すればプログラムを実行することができます。

```terminal
$ gfortran main.f90 #コンパイル
$ ./a.out #プログラム実行
total =    55.000000000000000
```

## 変数
```
型 :: 変数名
```

- 実数
    - 単精度実数(32bit, 6-7桁) real
    - 倍精度実数(64bit, 14-16桁) real(8)
- 複素数型
    - 単精度 complex
    - 倍精度 complex


##### 配列
配列にするときは、型 :: 変数名(要素数) にすればOK.
```fortran
real(8) :: numbers(100)
real(8) :: matrix(10, 10) !多次元配列
```
###### 割付け配列
配列のサイズが初期設定として定まらない時には、allocatableという属性をつけると
後からサイズを定義することができる。
```fortran
real(8), allocatable :: r(:)
integer :: n = 2

allocate (r(n)) ! n=2を割り付ける
! hoge
deallocate (r) ! 割付を解除する

``` 

##### 構造体
自分で定義できる型。
複数の型を要素として持つことができる。
```
type :: name
    integer :: nums
    real(8) :: total
end type name
```


## do, while, if
```fortran
! doループ
do i = min, max
    ! 実行文
enddo

! while ループ
do while (condition)
    ! 実行文
end do

! if文
if (論理式) then
    ! 実行文
else if (論理式) then
    ! 実行文
else
    ! 実行文
    ! ex)
    stop 'error! something is wrong!' !stop文を使うとエラーを検知できる
endif
```

## ファイル入出力
```fortran
! 入力
open(10, file='input.dat') ! ファイル番号10で入力ファイルinput.datを開く
read(10, *) x1 ! 1行目の値をx1に代入
read(10, *) x2 ! 2行目の値をx2に代入
close(10) ! ファイルを閉じる

! 出力
open(20, file='output.dat', status='replace') ! ファイル番号20でoutput.datを開く
write(20, *) result1, result2 ! 出力する
close(20) 
```
ファイル番号は任意でOkです.
出力する時のopen(ファイル番号,file=ファイル名, status='?')のstatus:
- old: 事前にファイルが存在している
- new: 事前に存在してはいけない
- replace: 事前に存在していてもしなくてもどっちでもOK


## 標準入出力
```fortran
integer :: i
! 入力
read(*,*) i ! 標準入力のinputされた値をiに代入する
! 出力
write(*,*) 'your input i = ', i ! 「your input i = iの値」を標準出力する
```

# 副プログラム編
module, subroutine, functionを理解するために以下のプログラムをみてください。
内容は最初のプログラムを同じで1からnまでの総和を取るだけです。
それをmodule, subroutine, functionを使って書いています。
```fortran
module utils
    implicit none
    
contains
    ! subroutine
    ! 配列の総和を計算する
    subroutine calc_total(nums, n, total)
    implicit none
    integer, intent(in) :: n
    real(8), intent(in) :: nums(n)
    real(8), intent(out) :: total

    total = 0.d0
    total = sum(nums) ! 総和をとる
    
    end subroutine calc_total

    ! function
    ! 1からnまでを要素として格納した配列を返す
    function make_nums(n) result(nums)
        implicit none
        integer, intent(in) :: n
        real(8) :: nums(n)
        integer :: i

        ! 配列に1からnを追加する
        do i = 1, n
            nums(i) = i
        end do
        
    end function make_nums
end module utils

program main
    use utils ! moduleを呼び出す
    implicit none ! 暗黙の変数の型に関する規則(変数の先頭がi~nまでだと整数、それ以 外では実数になるという規則)を無効にする

    ! ---------変数定義 ----------------------------------------
    integer :: i
    integer :: n
    real(8), allocatable :: nums(:)
    real(8) :: total
    !real(8) :: factor
    integer, parameter :: XNUM = 100
    real(8) :: xs(XNUM), ys(XNUM)

    ! ---------実行文 ----------------------------------------
    
    !標準入力
    write(*,*) 'input n : '
    read(*,*) n

    ! 配列numsのサイズをnに割り当てる
    allocate(nums(n))

    ! function
    ! 1からnを配列numsに格納する
    nums = make_nums(n)

    ! subroutine
    ! 配列numsの要素の総和を計算してtotalに代入する
    call calc_total(nums, n, total)

    ! 配列numsを解放する
    deallocate(nums)
    
    ! 標準出力
    ! write(ファイル番号, 書式) 出力対象1, 出力対象2,,,
    ! ファイル番号に* -> 標準出力
    ! 書式に* -> 並び出力(write文の後に並ぶ変数の型にあった書式で出力される)
    write(*, *) 'total = ', total

    ! ファイル出力
    open(20, file='output.dat', status='replace')
    write(20,*) total
    close(20) 

end program main
```

## Subroutine
- 書き方
```fortran
subroutine function_name(arg1, arg2, arg3)
    implicit none
    型, intent(in) :: arg1
    型, intent(in) :: arg2
    型, intent(out) :: total
    ! 実行文
    end subroutine calc_total
```
- 呼び出し方
```fortran
call subroutine(arg,,,)
```
- 説明
    - サブルーチン内でのみ使う引数(仮引数)にはintent(in)属性をつける
    - サブルーチン呼び出し後に戻る変数にはintent(out)属性をつける
    - 前回の値を保持させるには、save属性をつける

## Function
- 書き方
```fortran
function name(args,,,) result(output)
    implicit none
    ! 変数宣言
    型, intent(in) :: arg
    ,,,,
    型 :: output

    !実行文
end function name
```
- 呼び出し方
```fortran
function_name(引数,,,)
```
- 説明
    - 関数は単一の変数(output)を返し、引数に演算結果を格納しない
    - result句内の変数を返す
    - 返す変数は決まっているため、intent(in)属性だけ付ける

## module
- 書き方
```fortran
module name
    implicit none
contains
! 中身
! submodule, functionなど
end module name
```
- 呼び出し方
```fortran
use module_name
```
- 補足
    - module内でグローバル変数を定義するときは、save属性をつける


# 参考
数値計算のためのFortran90/95プログラミング入門, 牛島省, 森北出版株式会社