超音波流体屋のプログラム備忘録

PETSc

最終更新:

usapfrog

- view
管理者のみ編集可
PETScとはC/Fortranで使える、反復解法スパースソルバで有力なオープンソースコード。
PETScの入門的な使い方として、連立方程式の求解の計算例を示す。
https://www.mcs.anl.gov/petsc/index.html

インストール

https://www.mcs.anl.gov/petsc/documentation/installation.html
make installがないので、使用予定の場所に解凍する。 (2016/10/20編集)
OpenMPI環境で$MPI_ROOTにインストールされている場合下記が多分よい。
(追記)blas,lapackがyumで手に入っているなら--downloadの部分も不要。
その際libblas.soおよびliblapack.soにアクセスできるよう、適切なシンボリックリンクを貼ること。
./configure --with-mpi-dir=$MPI_ROOT --download-fblaslapack --with-scalar-type=complex --prefix=/usr/local/petsc
make all test
sudo make install

解凍後に表示される環境変数などを.bashrcなどに登録しておくとよい
export PETSC_DIR=/usr/local/petsc
export PETSC_ADIR=$PETSC_DIR
export PETSC_INC=$PETSC_DIR/include
export PETSC_AINC=$PETSC_ADIR/include
export PETSC_LIB=$PETSC_ADIR/lib
export LD_LIBRARY_PATH=$PETSC_LIB:$LD_LIBRARY_PATH

コンパイルなど

ifortがFPATHを見てくれみたいなので、-Iオプションでインクルードパスを指定
ifort hoge.f90 -o hoge.out -fpp -lpetsc -I${PETSC_INC} -I${PETSC_AINC}

ベクトルの入力

ベクトル・行列ともにアクセス方法は三種類で、
VecSetValueで個別に指定するか、VecSetValuesでインデックスと値とともに指定するか、
ポインタを取得・再格納するかに限られると思う。
PetscScalarは上記設定でインストールした場合complex(8)として扱える。
行列の格納はほとんどベクトルと似た関数が用意されている。

注意点としてVecSetValue(s)は引数に直接1d0などのreal(8)型を指定すると、
周囲の要素を壊してしまう傾向にあるため、一旦PetScScalarに格納するのが安全である。
  1. program petsc_test
  2. implicit none
  3. #include <petsc/finclude/petscsys.h>
  4. #include <petsc/finclude/petscvec.h>
  5. #include <petsc/finclude/petscvec.h90>
  6.  
  7. integer, parameter :: n = 4
  8. integer :: ierr, idx(n)
  9. Vec :: v
  10. PetscScalar, pointer :: p_v(:)
  11. PetscScalar :: val(n), x
  12.  
  13. val(:) = 1d0; val(3) = 4d0;
  14. idx = (/0,1,2,3/) !0 start indexに注意
  15.  
  16. call PetscInitialize(PETSC_NULL_CHARACTER,ierr)
  17. call VecCreateSeq(PETSC_COMM_SELF, n, v,ierr)
  18.  
  19. call VecSetValues(v, n, idx, val, INSERT_VALUES, ierr)
  20. x = 3d0 !手間だが一旦格納する
  21. call VecSetValue(v, 1, x, INSERT_VALUES,ierr) !idx:1 (0 startに注意)
  22.  
  23. call VecGetArrayF90(v,p_v,ierr)
  24. p_v(1) = (2d0, -4d0)
  25. call VecRestoreArrayF90(v,p_v,ierr)
  26.  
  27. call VecView(v, PETSC_VIEWER_STDOUT_SELF, ierr)
  28.  
  29. call VecDestroy(v,ierr)
  30. call PetscFinalize(ierr)
  31.  
  32. end program petsc_test
  33.  
結果:
Vec Object: 1 MPI processes
  type: seq
2. - 4. i
3.
4.
1.

行列の入力・連立方程式の求解

スパース行列を扱う上ではポインタ取得をするよりかは、MatSetValuesを使用するとよいと思う。
データ管理はPETScサイドでやってくれるので、COOやらCSRやら悩まないで済む。
行列は入力を終えたらMatAssemblyBegin/Endをしないとエラーになる。
反復/直接解法はKSP(Krylov SubsPace method)の構造体から行う。
直接解法は前処理からLUやCHOLESKYを選択すれば実施できる。
  1. program petsc_mat
  2. implicit none
  3.  
  4. #include <petsc/finclude/petscsys.h>
  5. #include <petsc/finclude/petscvec.h>
  6. #include <petsc/finclude/petscvec.h90>
  7. #include <petsc/finclude/petscmat.h>
  8. #include <petsc/finclude/petscksp.h>
  9. #include <petsc/finclude/petscpc.h>
  10.  
  11. integer, parameter :: n = 3
  12. integer :: ierr, idx(n), iter
  13. PetscScalar :: v(n), zero
  14. Mat :: a
  15. Vec :: b, x
  16.  
  17. KSP :: ksp !連立方程式ソルバ構造体
  18. PC :: pc !前処理構造体
  19. KSPConvergedReason :: res
  20. integer(8) :: clock1, clock2, crate, cmax !時間計測用
  21.  
  22. call PetscInitialize(PETSC_NULL_CHARACTER,ierr)
  23. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  24. !Mat prep.
  25. call MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,n,PETSC_NULL_INTEGER,a,ierr)
  26. v(:) = (/8d0, 1d0, 6d0/)
  27. call MatSetValues(a, 1, 0, n, (/0,1,2/), v, INSERT_VALUES,ierr)
  28. v(:) = (/3d0, 5d0, 7d0/)
  29. call MatSetValues(a, 1, 1, n, (/0,1,2/), v, INSERT_VALUES,ierr)
  30. v(:) = (/4d0, 9d0, 2d0/)
  31. call MatSetValues(a, 1, 2, n, (/0,1,2/), v, INSERT_VALUES,ierr)
  32. call MatAssemblyBegin(a, MAT_FINAL_ASSEMBLY,ierr)
  33. call MatAssemblyEnd(a,MAT_FINAL_ASSEMBLY,ierr)
  34. call MatView(a, PETSC_VIEWER_STDOUT_SELF, ierr)
  35.  
  36. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  37. !Vec prep.
  38. call VecCreateSeq(PETSC_COMM_SELF, n, b,ierr)
  39. v(:) = (/1d0, 1d0, 1d0/)
  40. call VecSetValues(b, n, (/0,1,2/), v, INSERT_VALUES,ierr)
  41. call VecView(b, PETSC_VIEWER_STDOUT_SELF, ierr)
  42.  
  43. call VecDuplicate(b,x,ierr)
  44. zero = 0d0 !1d0/15d0 !で初期値ありにするとイタレーションが0になる
  45. call VecSet(x,zero,ierr) !あらかじめ初期値を指定できる
  46.  
  47. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  48. !KSP prep. (Krylov SubsPace method)
  49. call KSPCreate(PETSC_COMM_SELF,ksp,ierr)
  50. call KSPSetType(ksp, KSPBICG, ierr) !何も指定しないとGMRESが入る
  51. !KSPTYPEはKSPのあとに, CG, BICG, MINRES, GMRES, BCGS(=biCgStab)
  52.  
  53. call KSPSetOperators(ksp,a,a,ierr) !前のaは解く行列,後ろは前処理用(同じでよい)
  54. call KSPSetInitialGuessNonzero(ksp,PETSC_TRUE,ierr) !指定しないとゼロ初期値で解く
  55.  
  56. call KSPGetPC(ksp,pc,ierr)
  57. call PCSetType(pc,PCJACOBI,ierr)
  58. !PCTYPEはPCのあとにJACOBI, ILU, ICC(不完全cholesky), LU, CHOLESKY(直接法)
  59.  
  60. call KSPSetTolerances(ksp,1d-9,PETSC_DEFAULT_REAL,PETSC_DEFAULT_REAL,PETSC_DEFAULT_INTEGER,ierr)
  61. call KSPSetFromOptions(ksp,ierr)
  62. call KSPView(ksp,PETSC_VIEWER_STDOUT_SELF,ierr) !オプションのレビュー
  63.  
  64. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  65. !Solve
  66. call system_clock(clock1,crate,cmax)
  67. call KSPSolve(ksp,b,x,ierr)
  68. call system_clock(clock2,crate,cmax)
  69.  
  70. call KSPGetIterationNumber(ksp,iter,ierr)
  71. call KSPGetConvergedReason(ksp, res, ierr) !正なら収束, 負なら発散
  72. ! 1,2:rtol, 3,9:atol, -3:its, -4:dtol, -5,6:breakdown, -9:nan/inf
  73. ! -7:non-sym, -8,10:indefinite, -11:pcfail
  74. print *, 'Status:', res, 'Iterations:', iter, ', time [s]', real(clock2 -clock1)/real(crate)
  75.  
  76. call VecView(x, PETSC_VIEWER_STDOUT_SELF, ierr)
  77.  
  78. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  79. !Finalize
  80. call KSPDestroy(ksp,ierr)
  81. call MatDestroy(a,ierr)
  82. call VecDestroy(b,ierr)
  83. call PetscFinalize(ierr)
  84.  
  85. end program petsc_mat
  86.  
結果
Mat Object: 1 MPI processes
  type: seqaij
row 0: (0, 8.)  (1, 1.)  (2, 6.) 
row 1: (0, 3.)  (1, 5.)  (2, 7.) 
row 2: (0, 4.)  (1, 9.)  (2, 2.) 
Vec Object: 1 MPI processes
  type: seq
1.
1.
1.
KSP Object: 1 MPI processes
  type: bicg
  maximum iterations=10000
  tolerances:  relative=1e-09, absolute=1e-50, divergence=10000.
  left preconditioning
  using nonzero initial guess
  using DEFAULT norm type for convergence test
PC Object: 1 MPI processes
  type: jacobi
  PC has not been set up so information may be incomplete
  linear system matrix = precond matrix:
  Mat Object:   1 MPI processes
    type: seqaij
    rows=3, cols=3
    total: nonzeros=9, allocated nonzeros=9
    total number of mallocs used during MatSetValues calls =0
      using I-node routines: found 1 nodes, limit used is 5
 Status:           2 Iterations:           3 , time [s]  4.4999999E-04
Vec Object: 1 MPI processes
  type: seq
0.0666667
0.0666667
0.0666667


目安箱バナー