[Fortran] モジュール メモ

コンパイラはifort．
単語帳．毎回検索するのが面倒なので転載多め．元URLあり．
自前の検証メモも．

## 他ファイルの手続きをそのまま渡す

mymod1.f90にあるmysubという手続きをmymod2.f90でuseすると，他ファイルからは`use mymod2, only: mysub1`で使える

```Fortran:mymod1.f90
module mymod1
    implicit none

contains

subroutine mysub1
    write(*, *) 'hello'
end subroutine mysub1
end module mymod1
```

```Fortran:mysub2.f90
module mymod2
    use mymod1, only: mysub1 ! only以降ははなくても可
end module mymod2
```

```Fortran:main.f90
program main
    use mymod2, only: mysub1
    implicit none
    call mysub1 ! hello
end program main
```





## `use, only`で複数モジュールに重複した名前を定義可能

```Fortran
module mod10
    implicit none
    integer :: a = 10
end module mod10

module mod20
    implicit none
    integer :: a = 20
end module mod20

program main
    use mod10, only: a
!    use mod20, only: a
    implicit none
    write(*, *) a ! 10，もしmod10をコメントアウト＋mod20を使うと20
end program main
```

#### 使い方1

`only`句で使用する変数を明示するのが良いと考えられる．
なぜなら，これを省略するとコンパイルエラー（コンパイル時に検出してくれるのでありがたい）になるが，エラーの出る箇所は書き方によって変わるからである↓↓

```Fortran
! パターン1
    use mod10, only: a
    use mod20, only: a ! ここでエラー

! パターン2
    use mod10!, only: a
    use mod20, only: a ! ここでエラー

! パターン3
    use mod10, only: a ! ここでエラー
    use mod20!, only: a

! パターン4
    use mod10!, only: a
    use mod20!, only: a
    implicit none
    write(*, *) a ! ここでエラー
```

#### 使い方2

重複した変数の両方を使いたい場合，別名で参照する：
（@septcolorさんありがとうございます！）

```Fortran
program main
    use mod10, only: a10 => a
    use mod20, only: a20 => a
! use mod10, only: a10 => a, aをするとa10もaも(10として)使えるが…
    implicit none
    write(*, *) a10, a20 ! 10 20
!    write(*, *) a ! 本来の変数名は使えない
end program main
```



## 独立した関数と構造体のメソッドの速度は変わらない

これを使うと関数・サブルーチンの階層化が可能!?
以下の例の時間計測結果：

|ケース|no option [sec]|-flto [sec]|-ip [sec]|-ipo [sec]|
|:---|---:|---:|---:|---:|
|関数を直接使用| 5.82|5.81|5.81|5.86|
|構造体のメソッド使用| 5.89|5.89|5.90|5.94|

- 関数を直接使用する方が1%程度高速
    - 構造体経由の方が可読性が向上するなら許容範囲？
- link-time optimization関連のコンパイルオプションによる変化は小さい
    - @septcolorさんありがとうございます！
- 他のコンパイルオプションとの組み合わせ，構造体の中身が複雑化したときの速度は未検証
- 式は[Qiita@hanaata: 色々な言語で計算速度を比較してみた]
(https://qiita.com/hanaata/items/c91788bcac2a40f1bb05)を参照

```Fortran
module mymod
    implicit none

    type Funcs
        contains
        procedure :: mymethod => mymethod
    end type Funcs

    type(Funcs) :: myobj
contains

function myfunc(i) result (y) ! これが使いたい関数
    integer, intent(in) :: i
    real(8) :: y
    y = (-1.d0) ** dble(i) * (2.d0 * dble(i) + 1.d0) ** 0.1d0
end function myfunc


function mymethod(self, i) result(y) ! 中身は上の関数と同じだが構造体経由でアクセスする用
    class(Funcs), intent(in) :: self
    integer, intent(in) :: i
    real(8) :: y
    y = (-1.d0) ** dble(i) * (2.d0 * dble(i) + 1.d0) ** 0.1d0
end function mymethod

end module mymod


program main
    use mymod, only: myfunc, myobj
    implicit none
    integer, parameter :: n = 100, niter = 10
    integer :: itime, ix, iy, i, iiter
    real(8) :: a(n,n), time(niter)
    integer :: t1, t2, t_rate, t_max, diff
! 関数を直接使用
    time(:) = 0.d0
    do iiter = 1, niter
        call system_clock(t1)
        do itime = 1, 10 ** 4
            do iy = 1, n
                do ix = 1, n
                    do i = 0, n
                        a(ix,iy) = a(ix,iy) + myfunc(i)
                    enddo
                enddo
            enddo
        enddo
        call system_clock(t2, t_rate, t_max)
        if ( t2 < t1 ) then
            diff = (t_max - t1) + t2 + 1
        else
            diff = t2 - t1
        endif
        time(iiter) = diff / dble(t_rate)
    enddo
    write(*, *) sum(time) / dble(niter)

! 構造体のメソッド使用
    time(:) = 0.d0
    do iiter = 1, niter
        call system_clock(t1)
        do itime = 1, 10 ** 4
            do iy = 1, n
                do ix = 1, n
                    do i = 0, n
                        a(ix,iy) = a(ix,iy) + myobj%mymethod(i)
                    enddo
                enddo
            enddo
        enddo
        call system_clock(t2, t_rate, t_max)
        if ( t2 < t1 ) then
            diff = (t_max - t1) + t2 + 1
        else
            diff = t2 - t1
        endif
        time(iiter) = diff / dble(t_rate)
    enddo
    write(*, *) sum(time) / dble(niter)
end program main
```