1. 導入:なぜ「多態性」が重要なのか
数値計算のプログラムを書いていると、「似ているけれど計算式が少し違う」複数のモデルを扱うことがよくあります。例えば、「流体モデルA」と「流体モデルB」で、flux(流束)を計算する関数を別々に作ると、メインプログラムが条件分岐だらけになり、管理が非常に大変になります。
「多態性(ポリモーフィズム)」を使えば、共通のインターフェースでモデルを呼び出せるようになり、コードの保守性が劇的に向上します。今回は、Fortranの`class`引数と`select type`構文を使った、スマートな実装方法を解説します。
2. 基礎知識:多態性とは?
多態性とは、一つの手続き(関数やサブルーチン)が、受け取るデータの型に応じて「適切な動作を自動的に選択する」性質のことです。
Fortranでは、基底となる型を`class(base_model)`として引数に指定することで、その子孫にあたる様々な型のデータを受け取れるようになります。受け取った先で`select type`構文を使うと、「今渡されたのはどのモデルなのか?」を判断し、実行時に最適な処理を切り替えることができます。
3. 実装と解決策
実装のステップは以下の通りです。
1. 基底となる`type`を定義する。
2. 派生型で、基底型を継承する。
3. 手続きの引数を`class`型にして、`select type`で型を判別して計算式を切り替える。
これにより、新しいモデルを追加しても、メインの呼び出し側コードを書き換える必要がなくなります。
4. サンプルプログラム
以下のコードは、異なる物理モデルのfluxを一つのサブルーチンで計算する例です。
module physics_models
implicit none
! 基底型:すべてのモデルの親
type, abstract :: base_model
end type
! モデルA:例として線形モデル
type, extends(base_model) :: linear_model
end type
! モデルB:例として非線形モデル
type, extends(base_model) :: nonlinear_model
end type
contains
! 多態性を利用した手続き
subroutine calc_flux(this)
class(base_model), intent(in) :: this
! 実行時の型に応じて処理を振り分ける
select type (this)
type is (linear_model)
print , "線形モデルのflux計算を実行中..."
! ここに線形用の計算式を書く
type is (nonlinear_model)
print , "非線形モデルのflux計算を実行中..."
! ここに非線形用の計算式を書く
class default
print , "未対応のモデルです"
end select
end subroutine
end module
program main
use physics_models
type(linear_model) :: model_a
type(nonlinear_model) :: model_b
! 同じ手続き名で異なる計算が呼び出せる
call calc_flux(model_a)
call calc_flux(model_b)
end program
5. 応用・注意点:現場で役立つポイント
注意点: `select type`は非常に便利ですが、使いすぎると計算速度に影響が出る場合があります。特に計算のループの中で毎回型判定を行うとオーバーヘッドが大きくなるため、可能な限り「計算ループの外側」で型を決定し、ループ内では最適化された手続きを呼び出すのがコツです。
回避策: もし計算速度が極端に重要な場合は、`select type`の代わりに「型ごとの手続きポインタ」を事前に割り当てておく手法(vtableのような仕組み)も検討してみてください。まずはこの`select type`でコードの整理を進め、ボトルネックが発生した際に最適化を行うのが、初心者の方にとって最も安全で確実なステップアップです。

コメント