MPI自動領域分割テンプレート

3次元ブロック分割のテンプレート、置いておきますね。 Fortran 90/95 で書いてます。

こちら

今まで自分でプロセスを割り当てていたのだけれど、MPIに自動でやってもらうと物理的な配置とかを考えて最適化した割り当てを提供してくれるっぽいので、お試しのつもりでやってみた。
もっと凝った配置をやりたい場合は自分で書く。

コード解説

使い方は簡単。 並列化したいメインプログラムの最初で init_parallel を呼びだす。 最後に fin_parallel を呼び出す。これだけ。

変数

ランク情報は変数 ranks でまとめて所持。 ranks%me は自分、ranks%xin はx方向の内側の通信相手、ranks%xout は外側の通信相手。 y, z についても同様。

変数 cart3d では座標分割に関する情報をまとめている。 cart3d%comm がコミュニケータで、集団通信なんかにはこいつを使う。 cart3d%dims には各次元の分割数を格納してある。 当然ながら、cart3d%comm と cart3d%dims はプロセッサ間で同じ値である。 自分が各次元の何番目のブロックに割り当てられているのかを知るには、cart3d%coords を参照すればよい。 物理座標の生成や並列IOなんかに使う。

初期化ルーチン

MPI_INIT でMPI初期化。全プロセス数 nprocs は MPI_COMM_SIZE で取得できる。 自分のランク ranks%me は MPI_COMM_RANK で取得。 このへんはMPIに触れたことがある人なら常識だとおもう。

残りのコードが問題の自動分割。

まず MPI_DIMS_CREATE の呼び出しで nprocs 個のプロセスを因数分解して、いい塩梅で Nx×Ny×Nz (Nx >= Ny >= Nz) に振り分けてくれる。 このとき cart3d%dims にあらかじめ非ゼロ要素を入れておくと尊重してくれる。 たとえばx方向は2分割で固定したい、とかそんなときに使える。

最適な分割数が分かったので、MPI_CART_CREATE でプロセスを実際に割り当てる。 周期境界でない場合は is_periodic = .false. にしておく。 reorder = .false. にしておくと、MPI_COMM_WORLD 内のランクと cart3d%comm 内でのランクが一致する。 特に問題なければ .true. にしておくのが吉か。

流体の場合には、境界の計算をするときに隣り合うプロセスからデータをもらう必要がある。 MPI_CART_SHIFT は隣接領域を担当するプロセスを見つけてきてランクを教えてくれるので、これを ranks%xin, ranks%xout などに格納しておく。

最後の MPI_CART_COORDS は、上で述べた cart3d%coords を知るためのルーチン。

各サブルーチンの詳細な使い方は MPICH2 または openMPI のマニュアルを参照。