LoginSignup
0
0

Fortranで有限要素法解析 05 : 2次元問題に拡張する

Last updated at Posted at 2024-06-12

前回,LAPACK の関数を cuSOLVER に置き換えて GPU オフロードを実現しました。そしてベンチマークを取って,cuSOLVER が大規模計算向きのツールであることを確認しました。

Fortranで有限要素法解析 04 : cuSOLVER を使う 〜 其の2 高速化 〜

そうであるならば,2次元問題の方が GPU 使用の優位性がより顕著に現れそうです(実際,1次元問題でそんなに多数のメッシュを取るケースはないだろうし,仮に CPU を使って解いたとしてもそのコストは高が知れており 1次元問題でGPUを使うメリットは考えにくい)。
そこで,2次元問題に対して同様の GPU 移植と計算速度の比較を試みてみます。

LSVQR

1次元問題でも使用した cuSOLVER の LSVQR(疎行列用の関数)を使用します。2次元問題では係数行列がブロック三重対角になることが異なりますが,それ以外の基本的なアルゴリズム構造は同じです。従って,1次元問題のときに省略した説明を中心に書いていきたいと思います。

メインプログラムは次のようになります。
温度分布を初期化(initialize)した後, それらを GPU にコピー(fem2d_to_device)してから時間ループのイテレーション(evolve)を実行します。最終結果はプログラムの最後で CPU に戻します(fem2d_to_host)。また,必要に応じて,イテレーションの最中に経過データを出力します。
ここで,temperature に u と u_work の2種類があるのは,時間方向に前進差分スキームを使っているからで,一方(既知時刻のデータ)を代数方程式の右辺に,他方(未知時刻のデータ)を左辺に使用して温度分布を更新していきます。

heat2d.f90
program heat2d
  ...
  
  call initialize(nx, ny, temperature)

  call fem2d_to_device(nx*ny, nx, ny, temperature%u, temperature%u_work)

  do iter = 1, nsteps
    call evolve(temperature, kappa, dt)
    if (mod(iter,out_interval) == 0) then
      !$acc update host(temperature%u)
      call plot(temperature%u)
    end if
  end do

  call fem2d_to_host(nx*ny, nx, ny, temperature%u, temperature%u_work)
  
end program

ホスト - デバイス間のデータコピーのルーチン(fem2d_to_device, fem2d_to_host)はそれぞれ次のようになります。

fem2d_to_device
subroutine fem2d_to_device(n, nx, ny, u, u_work)
  integer, intent(in) :: n, nx, ny
  real(real64), intent(inout) :: u(nx, ny), u_work(nx, ny)

  associate(bvec=>u_work, xvec=>u)

  !$acc enter data copyin(xvec) &
  !$acc            create(csrValA, csrRowPtrA, csrColIndA, bvec)

  end associate

end subroutine
fem2d_to_host
subroutine fem2d_to_host(n, nx, ny, u, u_work)
  integer, intent(in) :: n, nx, ny
  real(real64), intent(inout) :: u(nx, ny), u_work(nx, ny)

  associate(bvec=>u_work, xvec=>u)

  !$acc exit data copyout(xvec) &
  !$acc           delete(csrValA, csrRowPtrA, csrColIndA, bvec)

  end associate

end subroutine fem2d_to_host

代数方程式を解くプロセスは 1 次元のときと同じです。係数行列の作成(assemble_matrix), 右辺ベクトルの作成(assemble_rhs), 求解(solve_cusolver_sp)の順に行います。

計算結果は次のようになりました(中心付近の熱が周辺に拡散していっています)。

temperature_200.pngtemperature_400.pngtemperature_800.png

ベンチマーク

ステップ数 100 までの計算時間を,LAPACK を使用した CPU コードと cuSOLVER を使用した GPU 移植コードで比較しました(単位は秒)。残念ながら最大規模の計算は CPU で実行できませんでしたが(メモリ不足),計算規模が大きいとき,GPU の方に優位性が移りそうだと見て取れます。

ソルバ デバイス n=64$\times$64 n=128$\times$128 n=192$\times$192 n=256$\times$256
GBTRF/GBTRS(帯行列 LAPACK) CPU 3.9 58.0 269.6
LSVQR(疎行列 cuSOLVER) GPU w/ OpenACC 11.1 90.3 319.8 827.8
LSVQR(疎行列 cuSOLVER) GPU w/ OpenMP 11.1 89.5 321.6 830.9
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0