120
長岡技術科学大学電気電子情報工学専攻 出川智啓 GPGPU講習会 CUDA Fortranによる格子ボルツマン法の高速化

GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

  • Upload
    -

  • View
    646

  • Download
    5

Embed Size (px)

Citation preview

Page 1: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

長岡技術科学大学電気電子情報工学専攻 出川智啓

GPGPU講習会CUDA Fortranによる格子ボルツマン法の高速化

Page 2: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

本講習会の目標

GPGPU先端シミュレーションシステムの使用方法の習得

GPUの活用方法の修得

CUDAプログラミング技法の修得

並列計算手法の修得

2016/1/13GPGPU講習会2

Page 3: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

本日の内容

2016/1/13GPGPU講習会3

CUDA Fortranによる流体アプリケーションの高速化

格子ボルツマン法

D2Q9モデル

単純なGPU実装

使用メモリやデータ構造の 適化

雑多な高速化手法

Page 4: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

格子ボルツマン法

Page 5: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

スケール

2016/1/13GPGPU講習会5

巨視的スケール

連続体近似

偏微分方程式に対する数値計算法を利用

差分法,有限要素法,有限体積法等

非線形性,大規模連立一次方程式などの困難さ

微視的スケール

分子動力学

個々の原子の挙動を取り扱う

非現実的な計算量(1022個/リットル)

粒子の集合 微視的モデルと巨視的運動方程式

粒子の分布関数の時間発展方程式を計算

Page 6: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

支配方程式

2016/1/13GPGPU講習会6

粒子の分布関数の時間発展方程式

BGKモデル

衝突項を簡単化

Bhatnagar‐Gross‐Krook方程式

)(),(),( ftfttf ppp

p

xcx

f : 粒子の分布関数 c : 粒子の移流速度

t : 時間 x : 直交格子上の位置ベクトルp : 粒子の番号(方向)

: 衝突項

),(),(1),(),( xxxcx tftftfttf p

eqppp

p

: 緩和時間feq : 局所平衡分布関数

Page 7: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

方程式の離散化

2016/1/13GPGPU講習会7

粒子の分布関数

格子BGK方程式

初期値,境界値問題として解く

),(),(1),(),( xxxcx tftftfΔtΔttf peq

pppp

),(),(1),(),( xxxcx tftftfttf p

eqppp

p

時間離散化(1次精度Euler法)

空間離散化(1次精度上流差分)

Page 8: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロ量の計算

2016/1/13GPGPU講習会8

マクロ量(いわゆる流体の物理量)の定義

温度変化を取り扱わない

密度

速度ベクトルu

1

0

N

p

pf

1

0

N

p

pi

pi cfu より N : 座標xにおける粒子の個数

1

0

N

p

pi

pi cfu

i : 空間方向

粒子番号は0~N−1

x1

x2

Page 9: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

D2Q9モデル

2016/1/13GPGPU講習会9

0 1

2

3

4

56

7 8

格子点上に9個の粒子があり,t秒後に周囲8格子点に粒子が移動

一つはその場にとどまる

移動方向に応じた移流速度を定義

Page 10: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

D2Q9モデル

2016/1/13GPGPU講習会10

22 5.1)(

29)(31 uucucpp wf

0 1

2

3

4

56

7 8

分布関数と重み係数,移流速度ベクトル

方向p 移流速度 重み係数

0 ( 0, 0) 4/9

1 ( 1, 0) 1/9

2 ( 0, 1) 1/9

3 (‐1, 0) 1/9

4 ( 0,‐1) 1/9

5 ( 1, 1) 1/36

6 (‐1, 1) 1/36

7 (‐1,‐1) 1/36

8 ( 1,‐1) 1/36i i+1i−1

j

j+1

j−1

Page 11: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Collision Step

2016/1/13GPGPU講習会11

衝突項の計算

粒子の移動に伴う相互作用

他格子にある粒子の情報を必要としない

局所的(1点完結)で簡単な計算

並列計算に 適

),(),(1),(),(~

xxxx tftftftf peq

ppp

f(p,i,j) = f(p,i,j)‐(f(p,i,j)‐f_eq(p,i,j))/

Page 12: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

粒子の移動

粒子自身の移流速度によって隣の格子点へ移動

単純なメモリコピー

Stream Step

2016/1/13GPGPU講習会12

),(~

),( xcx tfΔtΔttf ppp

03 147 8

26 5

i i+1i−1

j

j+1

j−1

Page 13: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

粒子の移動

粒子自身の移流速度によって隣の格子点へ移動

単純なメモリコピー

Stream Step

2016/1/13GPGPU講習会13

),(~

),( xcx tfΔtΔttf ppp

03 1

47 8

26 5

f(0,i  ,j  ) = f(0,i,j)f(1,i+1,j  ) = f(1,i,j)f(2,i  ,j+1) = f(2,i,j)f(3,i‐1,j  ) = f(3,i,j)f(4,i  ,j‐1) = f(4,i,j)

:

i i+1i−1

j

j+1

j−1

Page 14: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会14

マクロ量に対する境界条件から粒子の分布関数を決定

流入・流出境界条件

ここでは取り扱わない

固定壁境界条件

壁面が格子点上に存在

すべり無し条件

Bounce Back 移動壁境界条件(Zou‐Heの境界条件)

Page 15: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Bounce Back

2016/1/13GPGPU講習会15

すべり無し壁の境界条件

固体壁に入射した粒子は入射した方向に跳ね返る

単純だが非常に効果的

03 147 8

26 503 147 8

26 5

Page 16: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Bounce Back

2016/1/13GPGPU講習会16

すべり無し壁の境界条件

固体壁に入射した粒子は入射した方向に跳ね返る

単純だが非常に効果的

0 1

4 8

2 5

03 126 5

15

26 5

8

Page 17: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Zou-He境界条件

2016/1/13GPGPU講習会17

境界で速度が規定されている場合の分布関数の決定法

他格子点の情報を必要としない局所的な方法

計算領域内の分布関数と密度と流束(u1,u2)を連立

Zou,Q. and He,X., Phys. Fluids, 9(1997), 1591‐1598

03 126 5

f 7 , f 4, f 8をf 0, f 1, f 2, f 3, f 5, f 6

と境界上の速度から決定

流入境界(法線方向速度が存在する場合)にも適用可能

U

652310 2 ffffffB 24 ff

6/57 Uff B

6/68 Uff B

47 8

Page 18: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Zou-He境界条件

2016/1/13GPGPU講習会18

境界で速度が規定されている場合の分布関数の決定法

他格子点の情報を必要としない局所的な方法

計算領域内の分布関数と密度と流束(u1,u2)を連立

Zou,Q. and He,X., Phys. Fluids, 9(1997), 1591‐1598

03 147 8

26 5

f 7 , f 4, f 8をf 0, f 1, f 2, f 3, f 5, f 6

と境界上の速度から決定

流入境界(法線方向速度が存在する場合)にも適用可能

U

652310 2 ffffffB 24 ff

6/57 Uff B

6/68 Uff B 47 8

Page 19: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

U

粒子運動のイメージ(Stream)

2016/1/13GPGPU講習会19

03 147 8

26 503 147 8

26 5

03 147 8

26 503 147 8

26 5

0326

03 126 5

03 126 5

0 12 5

0 14 8

2 5

0 14 8

2 5

0 14 8

2 503 147 8

26 503 147 8

26 5

0347

26

0347

26

0347

2637

6

37

6

37

6

37

6

47 847 84 8 47

18

5

18

5

18

15

8

5

Page 20: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

U

粒子運動のイメージ(境界条件)

2016/1/13GPGPU講習会20

03 147 8

26 503 147 8

26 5

03 147 8

26 503 147 8

26 5

0326

03 126 5

03 126 5

0 12 5

0 14 8

2 5

0 14 8

2 5

0 14 8

2 503 147 8

26 503 147 8

26 5

0347

26

0347

26

0347

2637

6

37

6

37

6

37

6

47 847 84 8 47

18

5

18

5

18

15

8

5

Page 21: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

計算手順

2016/1/13GPGPU講習会21

1. 初期流れ場のマクロな密度と速度u1, u2を定める

2. 局所平衡分布関数feqを計算する

3. 衝突項を計算する

4. 粒子を移流させる

5. 境界条件を計算する

6. マクロな密度と速度u1, u2を計算する

7. feqを分布関数fとし,2に戻って繰り返す

Page 22: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

LBMプログラムの作成

2016/1/13GPGPU講習会22

Fortran 90/95, CUDA Fortranを利用

キャビティ流れを計算

溝の上に置かれたフタが一定速度で移動

初期条件

静止状態

密度一定

速度0 境界条件

左右,下壁面は固定壁

上壁面のみ移動壁x

y

Page 23: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

計算用パラメータ

2016/1/13GPGPU講習会23

物理空間におけるパラメータとボルツマン法の離散空間におけるパラメータの対応付けが必要

非圧縮性粘性流れに必要なパラメータ

長さ

時間

動粘度

レイノルズ数=長さ×速度/動粘度=長さ2/時間/動粘度

速度=長さ/時間

Page 24: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

計算用パラメータ

2016/1/13GPGPU講習会24

物理空間

代表長さ[m] L 代表速度[m/s] U 代表時間[s] T=L/U 動粘度[m2/s] レイノルズ数[-] Re=LU/=L2/T/

物理空間(無次元化)

代表長さ[-] L*=1 代表時間[-] T*=1 代表速度[-] U*=L*/T*=1 動粘度[-] *=1/Re

Page 25: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

計算用パラメータ

2016/1/13GPGPU講習会25

LBM離散空間

代表長さ[-] LLB

代表時間[-] TLB

速度[-] ULB=TLBU*/LLB=TLB/LLB

動粘度[-] LB=TLB/LLB2/Re

緩和時間[-] =3LB+0.5

代表時間の決定

代表時間 TLB≈LLB2

圧縮性に関係する誤差の議論から導出

差分法等Euler系解法における数値安定性と同様

Page 26: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

module SimulationParameterimplicit noneinteger,parameter :: Nt = 50000real(8),parameter :: Re = 1000d0

integer,parameter :: NumCell_x = 512integer,parameter :: NumCell_y = NumCell_xinteger,parameter :: Nx = NumCell_xinteger,parameter :: Ny = NumCell_y

real(8),parameter :: dx = 1d0/dble(NumCell_x)real(8),parameter :: Uwall = 0.5d0            !dt/dxreal(8),parameter :: dt = Uwall*dx            !dx**2real(8),parameter :: KineticViscosity = Uwall/dx/Re 

real(8),parameter :: RelaxTime = 3d0*KineticViscosity + 0.5d0end module SimulationParameter

計算用パラメータ

2016/1/13GPGPU講習会26

module_SimulationParameter.f90

本来はdtを決めてからUwallを決める

source/cpu/に置いています

Page 27: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

integer,parameter :: Center    = 0integer,parameter :: Right     = 1integer,parameter :: Up        = 2integer,parameter :: Left      = 3integer,parameter :: Down      = 4integer,parameter :: UpRight = 5integer,parameter :: UpLeft = 6integer,parameter :: DownLeft = 7integer,parameter :: DownRight = 8integer,parameter :: First  = Centerinteger,parameter :: Last   = DownRightinteger,parameter :: Opposite(First:Last) = (/ Center, Left, Down, Right, Up,&

DownLeft, DownRight,UpRight,UpLeft/)

real(8),parameter :: Weight(First:Last) =(/4d0/ 9d0,&1d0/ 9d0, 1d0/ 9d0, 1d0/ 9d0, 1d0/ 9d0,&1d0/36d0, 1d0/36d0, 1d0/36d0, 1d0/36d0 /)

integer,parameter :: ConvVelx(First:Last) = (/ 0, 1, 0,‐1, 0, 1,‐1,‐1, 1 /)integer,parameter :: ConvVely(First:Last) = (/ 0, 0, 1, 0,‐1, 1, 1,‐1,‐1 /)

D2Q9モデル(パラメータ)

2016/1/13GPGPU講習会27

module_D2Q9Model.f90

Page 28: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

初期マクロ量の設定

2016/1/13GPGPU講習会28

subroutine computeIntialMacroQuantities(velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(inout) :: velx(Nx,Ny)real(8),intent(inout) :: vely(Nx,Ny)real(8),intent(inout) :: dens(Nx,Ny)

integer :: i,j

velx(:,:) = 0d0vely(:,:) = 0d0dens(:,:) = 1d0velx(2:Nx‐1,Ny) = Uwall

end subroutine computeIntialMacroQuantities

module_D2Q9Model.f90

Page 29: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会29

subroutine computeMacroQuantities(f,velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(in)    :: f(First:Last,1:Nx,1:Ny)real(8),intent(inout) :: velx(1:Nx,1:Ny)real(8),intent(inout) :: vely(1:Nx,1:Ny)real(8),intent(inout) :: dens(1:Nx,1:Ny)integer :: i,jreal(8) :: f_boundary, f_exterior

do j=1,Nydo i=1,Nx

dens(i,j) =   f(Center   ,i,j) + f(Right    ,i,j) + f(Up       ,i,j)&+ f(Left     ,i,j) + f(Down     ,i,j) + f(UpRight ,i,j)&+ f(UpLeft ,i,j) + f(DownLeft ,i,j) + f(DownRight,i,j)

end doend dodo i=2,Nx‐1

f_boundary = f(Center,i,Ny) + f(  Right,i,Ny) + f(  Left,i,Ny)f_exterior = f(Up    ,i,Ny) + f(UpRight,i,Ny) + f(UpLeft,i,Ny)dens(i,Ny) = f_boundary + 2d0*f_exterior

end do

module_D2Q9Model.f90

Page 30: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会30

do j=2,Ny‐1do i=2,Nx‐1

velx(i,j) = ( f(Center   ,i,j)*ConvVelx(Center   )&+f(Right    ,i,j)*ConvVelx(Right    )&+f(Up       ,i,j)*ConvVelx(Up       )&+f(Left     ,i,j)*ConvVelx(Left     )&+f(Down     ,i,j)*ConvVelx(Down     )&+f(UpRight ,i,j)*ConvVelx(UpRight )&+f(UpLeft ,i,j)*ConvVelx(UpLeft )&+f(DownLeft ,i,j)*ConvVelx(DownLeft )&+f(DownRight,i,j)*ConvVelx(DownRight))/dens(i,j)

vely(i,j) = ( f(Center   ,i,j)*ConvVely(Center   )&+f(Right    ,i,j)*ConvVely(Right    )&+f(Up       ,i,j)*ConvVely(Up       )&+f(Left     ,i,j)*ConvVely(Left     )&+f(Down     ,i,j)*ConvVely(Down     )&+f(UpRight ,i,j)*ConvVely(UpRight )&+f(UpLeft ,i,j)*ConvVely(UpLeft )&+f(DownLeft ,i,j)*ConvVely(DownLeft )&+f(DownRight,i,j)*ConvVely(DownRight))/dens(i,j)

end doend do

end subroutine computeMacroQuantities

module_D2Q9Model.f90

Page 31: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数

2016/1/13GPGPU講習会31

subroutine computeLocalEquilibriumFunction(f_eq,velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(inout) :: f_eq(First:Last,1:Nx,1:Ny)real(8),intent(in)    :: velx(1:Nx,1:Ny)real(8),intent(in)    :: vely(1:Nx,1:Ny)real(8),intent(in)    :: dens(1:Nx,1:Ny)real(8) :: u,v,conv_velo,velo_squareinteger :: i,j,direction

do j=1,Nydo i=1,Nx

u = velx(i,j)v = vely(i,j)velo_square = u*u + v*vdo direction = First,Last

conv_velo =  u*ConvVelx(direction) + v*ConvVely(direction)f_eq(direction,i,j) = Weight(direction)*dens(i,j)&

*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)end do

end doend do

end subroutine computeLocalEquilibriumFunction

module_D2Q9Model.f90

Page 32: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Collision Step

2016/1/13GPGPU講習会32

subroutine collide(f,f_eq)use SimulationParameterimplicit nonereal(8),intent(inout) :: f   (First:Last,1:Nx,1:Ny)real(8),intent(in)    :: f_eq(First:Last,1:Nx,1:Ny)

integer :: i,j,direction

do j=1,Nydo i=1,Nx

f(:,i,j) = f(:,i,j) + (f_eq(:,i,j)‐f(:,i,j))/RelaxTimeend doend do

end subroutine collide

module_D2Q9Model.f90

Page 33: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会33

subroutine stream(f)use SimulationParameterimplicit nonereal(8),intent(inout) :: f(First:Last,1:Nx,1:Ny)integer :: i,j

do j=1,Nydo i=Nx,2,‐1 !RIGHT TO LEFT

f(Right,i,j)=f(Right,i‐1,j)end dodo i=1,Nx‐1 !LEFT TO RIGHT

f(Left,i,j)=f(Left,i+1,j)end do

end do

module_D2Q9Model.f90

Page 34: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会34

do j=Ny,2,‐1 !TOP TO BOTTOMdo i=1,Nx

f(Up,i,j)=f(Up,i,j‐1)end dodo i=Nx,2,‐1

f(UpRight,i,j)=f(UpRight,i‐1,j‐1)end dodo i=1,Nx‐1

f(UpLeft,i,j)=f(UpLeft,i+1,j‐1)end do

end do do j=1,Ny‐1 !BOTTOM TO TOP

do i=1,Nxf(Down,i,j)=f(Down,i,j+1)

end dodo i=1,Nx‐1

f(DownLeft,i,j)=f(DownLeft,i+1,j+1)end dodo i=Nx,2,‐1

f(DownRight,i,j)=f(DownRight,i‐1,j+1)end do

end doend subroutine stream

module_D2Q9Model.f90

Page 35: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会35

subroutine imposeBoundayCondition(f)use SimulationParameterimplicit none

real(8),intent(inout) :: f(First:Last,1:Nx,1:Ny)

integer :: i,jreal(8) :: dens_wallreal(8) :: f_boundary, f_exterior

do j=1,Ny!bounce back on west boundaryf(    Right, 1,j) = f(Opposite(    Right), 1,j)f(  UpRight, 1,j) = f(Opposite(  UpRight), 1,j)f(DownRight, 1,j) = f(Opposite(DownRight), 1,j)!bounce back on east boundaryf(    Left ,Nx,j) = f(Opposite(    Left ),Nx,j)f(DownLeft ,Nx,j) = f(Opposite(DownLeft ),Nx,j)f(  UpLeft ,Nx,j) = f(Opposite(  UpLeft ),Nx,j)

end do

module_D2Q9Model.f90

Page 36: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会36

!bounce back on south boundarydo i=1,Nx

f(Up     ,i,1)=f(Opposite(Up     ),i,1)f(UpRight,i,1)=f(Opposite(UpRight),i,1)f(UpLeft ,i,1)=f(Opposite(UpLeft ),i,1)

end do!moving wall, north boundarydo i=2,Nx‐1

f_boundary = f(Center,i,Ny)+f(  Right,i,Ny)+f(  Left,i,Ny)f_exterior = f(Up    ,i,Ny)+f(UpRight,i,Ny)+f(UpLeft,i,Ny)dens_wall = f_boundary + 2d0*f_exteriorf(Down     ,i,Ny)=f(Opposite(Down     ),i,Ny)f(DownRight,i,Ny)=f(Opposite(DownRight),i,Ny) + dens_wall*Uwall/6.0f(DownLeft ,i,Ny)=f(Opposite(DownLeft ),i,Ny) ‐ dens_wall*Uwall/6.0

end do

end subroutine imposeBoundayCondition

module_D2Q9Model.f90

Page 37: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会37

program LBM_Cavityuse SimulationParameteruse D2Q9Modelimplicit nonereal(8),allocatable ::  velx(:,:) !マクロな速度ベクトルと密度real(8),allocatable ::  vely(:,:) !real(8),allocatable ::  dens(:,:) !real(8),allocatable :: f   (:,:,:)!分布関数real(8),allocatable :: f_eq(:,:,:)!局所平衡分布関数integer :: n

allocate( velx(1:Nx,1:Ny))allocate( vely(1:Nx,1:Ny))allocate( dens(1:Nx,1:Ny))   allocate(f   (First:Last,1:Nx,1:Ny))allocate(f_eq(First:Last,1:Nx,1:Ny))

lbm_cavity.f90

Page 38: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会38

call computeIntialMacroQuantities(velx,vely,dens)do n=1,Nt

call computeLocalEquilibriumFunction(f_eq,velx,vely,dens)call collide(f,f_eq)call stream(f)call imposeBoundayCondition(f)call computeMacroQuantities(f,velx,vely,dens)

end do

deallocate(f   )deallocate(f_eq)deallocate(velx)deallocate(vely)deallocate(dens)

end program LBM_Cavity

lbm_cavity.f90

Page 39: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

プログラムのコンパイル

2016/1/13GPGPU講習会39

コンパイラにはpgfortranを利用

pgf90でも可能

リンクせずにオブジェクトファイルを生成

$ pgf90 ‐c module_SimulationParameter.f90 $ pgf90 ‐c module_D2Q9Model.f90 $ pgf90 ‐c lbm_cavity.f90

オブジェクトファイルをリンクして実行ファイルを生成

$ pgf90 ‐o lbm_cavity *.o

Page 40: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

実行結果

2016/1/13GPGPU講習会40

計算条件

格子点数 512 移動壁の速度 0.5 レイノルズ数 1000 計算時間 0~50000

実行時間

512×512 52ms/step 1024×1024 214ms/step 2048×2048 900ms/step

u1−0.2 0.5

Page 41: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

GPUへの移植

2016/1/13GPGPU講習会41

とりあえずGPUで実行すればいいのなら・・・

拡張子を.cufに変更

use cudaforを追加

GPUの都合を反映

サブルーチンにattributes(global)を付ける

カーネル名と引数の間に<<<1,1>>>を付ける

GPUで使うメモリにdevice属性を付与

allocate()の変更は不要

GPUとのデータのやり取りには代入演算子(=)を使う

適化は追々考えればいい

Page 42: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

D2Q9モデルのパラメータの取扱

2016/1/13GPGPU講習会42

parameter属性のホストスカラ変数はカーネルから直接参照可能

GPUへの転送が不要

比較的古いバージョンのCUDA Fortranから可能

parameter属性が付いていても配列は参照不可能* D2Q9モデルの重み係数や移流速度は,GPU側の変数を宣言してコピー

* 近のCUDA Fortranではparameter属性付きの配列をカーネルから直接参照可能

配列添字は1開始に強制

integer,parameter :: a(0:8)と宣言しても,カーネルからはa(1:9)として利用しなければならない

Page 43: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

初期マクロ量の設定

2016/1/13GPGPU講習会43

attributes(global) subroutine computeIntialMacroQuantities(velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(inout),device :: velx(Nx,Ny)real(8),intent(inout),device :: vely(Nx,Ny)real(8),intent(inout),device :: dens(Nx,Ny)integer :: i,j

do j=1,Nydo i=1,Nx

velx(i,j) = 0d0vely(i,j) = 0d0dens(i,j) = 1d0

end doend doj=Nydo i=2,Nx‐1

velx(i,j) = Uwallend do

end subroutine computeIntialMacroQuantities

module_D2Q9Model.cuf

source/gpu/serial/に置いています

Page 44: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会44

attributes(global) subroutine computeMacroQuantities(f,velx,vely,dens,ConvVelx,ConvVely)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f(First:Last,1:Nx,1:Ny)real(8),intent(inout),device :: velx(1:Nx,1:Ny)real(8),intent(inout),device :: vely(1:Nx,1:Ny)real(8),intent(inout),device :: dens(1:Nx,1:Ny)integer,intent(in)   ,device :: ConvVelx(First:Last) !移流速度integer,intent(in)   ,device :: ConvVely(First:Last) !integer :: i,jreal(8) :: f_boundary, f_exteriordo j=1,Nydo i=1,Nx

dens(i,j) =  f(Center   ,i,j)+f(Right    ,i,j)+f(Up       ,i,j)&+f(Left     ,i,j)+f(Down     ,i,j)+f(UpRight ,i,j)&+f(UpLeft ,i,j)+f(DownLeft ,i,j)+f(DownRight,i,j)

end doend dodo i=2,Nx‐1

f_boundary = f(Center,i,Ny)+f(  Right,i,Ny)+f(  Left,i,Ny)f_exterior = f(Up    ,i,Ny)+f(UpRight,i,Ny)+f(UpLeft,i,Ny)dens(i,Ny) = f_boundary + 2d0*f_exterior

end do

module_D2Q9Model.cuf

Page 45: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会45

do j=2,Ny‐1do i=2,Nx‐1

velx(i,j) = ( f(Center   ,i,j)*ConvVelx(Center   )&+f(Right    ,i,j)*ConvVelx(Right    )&+f(Up       ,i,j)*ConvVelx(Up       )&+f(Left     ,i,j)*ConvVelx(Left     )&+f(Down     ,i,j)*ConvVelx(Down     )&+f(UpRight ,i,j)*ConvVelx(UpRight )&+f(UpLeft ,i,j)*ConvVelx(UpLeft )&+f(DownLeft ,i,j)*ConvVelx(DownLeft )&+f(DownRight,i,j)*ConvVelx(DownRight))/dens(i,j)

vely(i,j) = ( f(Center   ,i,j)*ConvVely(Center   )&+f(Right    ,i,j)*ConvVely(Right    )&+f(Up       ,i,j)*ConvVely(Up       )&+f(Left     ,i,j)*ConvVely(Left     )&+f(Down     ,i,j)*ConvVely(Down     )&+f(UpRight ,i,j)*ConvVely(UpRight )&+f(UpLeft ,i,j)*ConvVely(UpLeft )&+f(DownLeft ,i,j)*ConvVely(DownLeft )&+f(DownRight,i,j)*ConvVely(DownRight))/dens(i,j)

end doend do 

end subroutine computeMacroQuantities

module_D2Q9Model.cuf

Page 46: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数

2016/1/13GPGPU講習会46

attributes(global) &subroutine computeLocalEquilibriumFunction(f_eq,velx,vely,dens,ConvVelx,ConvVely,Weight)

use SimulationParameterimplicit nonereal(8),intent(inout),device :: f_eq(First:Last,1:Nx,1:Ny)real(8),intent(in)   ,device :: velx(1:Nx,1:Ny)real(8),intent(in)   ,device :: vely(1:Nx,1:Ny)real(8),intent(in)   ,device :: dens(1:Nx,1:Ny)integer,intent(in)   ,device :: ConvVelx(First:Last) !移流速度integer,intent(in)   ,device :: ConvVely(First:Last) !real(8),intent(in)   ,device :: Weight(First:Last)   !重み係数real(8) :: u,v,conv_velo,velo_squareinteger :: i,j,direction

module_D2Q9Model.cuf

Page 47: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数

2016/1/13GPGPU講習会47

do j=1,Nydo i=1,Nx

u = velx(i,j)v = vely(i,j)velo_square = u*u + v*vdo direction = First,Last

conv_velo =  u*ConvVelx(direction) + v*ConvVely(direction)f_eq(direction,i,j) = Weight(direction)*dens(i,j)&

*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)end do

end doend do

end subroutine computeLocalEquilibriumFunction

module_D2Q9Model.cuf

Page 48: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Collision Step

2016/1/13GPGPU講習会48

attributes(global) subroutine collide(f,f_eq)use SimulationParameterimplicit none

real(8),intent(inout),device :: f   (First:Last,1:Nx,1:Ny)real(8),intent(in)   ,device :: f_eq(First:Last,1:Nx,1:Ny)

integer :: i,j,direction

do j=1,Nydo i=1,Nx

f(:,i,j) = f(:,i,j) + (f_eq(:,i,j)‐f(:,i,j))/RelaxTimeend doend do

end subroutine collide

module_D2Q9Model.cuf

Page 49: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会49

attributes(global) subroutine stream(f)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)integer :: i,j

do j=1,Nydo i=Nx,2,‐1 !RIGHT TO LEFT

f(Right,i,j)=f(Right,i‐1,j)end dodo i=1,Nx‐1 !LEFT TO RIGHT

f(Left,i,j)=f(Left,i+1,j)end do

end do

module_D2Q9Model.cuf

Page 50: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会50

do j=Ny,2,‐1 !TOP TO BOTTOMdo i=1,Nx

f(Up,i,j)=f(Up,i,j‐1)end dodo i=Nx,2,‐1

f(UpRight,i,j)=f(UpRight,i‐1,j‐1)end dodo i=1,Nx‐1

f(UpLeft,i,j)=f(UpLeft,i+1,j‐1)end do

end dodo j=1,Ny‐1 !BOTTOM TO TOP

do i=1,Nxf(Down,i,j)=f(Down,i,j+1)

end dodo i=1,Nx‐1

f(DownLeft,i,j)=f(DownLeft,i+1,j+1)end dodo i=Nx,2,‐1

f(DownRight,i,j)=f(DownRight,i‐1,j+1)end do

end doend subroutine stream

module_D2Q9Model.cuf

Page 51: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会51

attributes(global) subroutine imposeBoundayCondition(f,Opposite)use SimulationParameterimplicit none

real(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)integer,intent(in)   ,device :: Opposite(First:Last)

integer :: i,jreal(8) :: dens_wallreal(8) :: f_boundary, f_exterior

do j=1,Ny!bounce back on west boundaryf(    Right, 1,j) = f(Opposite(    Right), 1,j)f(  UpRight, 1,j) = f(Opposite(  UpRight), 1,j)f(DownRight, 1,j) = f(Opposite(DownRight), 1,j)!bounce back on east boundaryf(    Left ,Nx,j) = f(Opposite(    Left ),Nx,j)f(DownLeft ,Nx,j) = f(Opposite(DownLeft ),Nx,j)f(  UpLeft ,Nx,j) = f(Opposite(  UpLeft ),Nx,j)

end do

module_D2Q9Model.cuf

Page 52: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会52

!bounce back on south boundarydo i=1,Nx

f(Up     ,i,1)=f(Opposite(Up     ),i,1)f(UpRight,i,1)=f(Opposite(UpRight),i,1)f(UpLeft ,i,1)=f(Opposite(UpLeft ),i,1)

end do!moving wall, north boundarydo i=2,Nx‐1

f_boundary = f(Center,i,Ny)+f(  Right,i,Ny)+f(  Left,i,Ny)f_exterior = f(Up    ,i,Ny)+f(UpRight,i,Ny)+f(UpLeft,i,Ny)dens_wall = f_boundary + 2d0*f_exteriorf(Down     ,i,Ny)=f(Opposite(Down     ),i,Ny)f(DownRight,i,Ny)=f(Opposite(DownRight),i,Ny) + dens_wall*Uwall/6.0f(DownLeft ,i,Ny)=f(Opposite(DownLeft ),i,Ny) ‐ dens_wall*Uwall/6.0

end do

end subroutine imposeBoundayCondition

module_D2Q9Model.cuf

Page 53: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会53

program LBM_Cavityuse cudaforuse SimulationParameteruse D2Q9Modelimplicit nonereal(8),allocatable,device ::  velx(:,:)real(8),allocatable,device ::  vely(:,:)real(8),allocatable,device ::  dens(:,:)

real(8),allocatable,device :: f   (:,:,:)real(8),allocatable,device :: f_eq(:,:,:)real(8),allocatable,device :: dev_Weight(:)integer,allocatable,device :: dev_ConvVelx(:)integer,allocatable,device :: dev_ConvVely(:)integer,allocatable,device :: dev_Opposite(:)

integer :: n,stat

lbm_cavity.cuf

Page 54: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会54

allocate( velx(1:Nx,1:Ny))allocate( vely(1:Nx,1:Ny))allocate( dens(1:Nx,1:Ny))

allocate(f   (First:Last,1:Nx,1:Ny));f   =0d0allocate(f_eq(First:Last,1:Nx,1:Ny));f_eq=0d0allocate(dev_Weight(First:Last));  dev_Weight =Weightallocate(dev_ConvVelx(First:Last));dev_ConvVelx=ConvVelxallocate(dev_ConvVely(First:Last));dev_ConvVely=ConvVelyallocate(dev_Opposite(First:Last));dev_Opposite=Opposite

lbm_cavity.cuf

Page 55: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会55

call computeIntialMacroQuantities<<<1,1>>>(velx,vely,dens)do n=1,Nt

call computeLocalEquilibriumFunction<<<1,1>>>(f_eq,velx,vely,dens,dev_ConvVelx,dev_ConvVely,dev_Weight)

call collide<<<1,1>>>(f,f_eq)call stream<<<1,1>>>(f)call imposeBoundayCondition<<<1,1>>>(f,dev_Opposite)call computeMacroQuantities<<<1,1>>>(f,velx,vely,dens,dev_ConvVelx,dev_ConvVely)stat = cudaThreadSynchronize() !バージョンが古いため,cudaDeviceSynchronizeは利用不可

end do

deallocate(f   )deallocate(f_eq)deallocate(velx)deallocate(vely)deallocate(dens)deallocate(dev_Weight)deallocate(dev_ConvVelx)deallocate(dev_ConvVely)deallocate(dev_Opposite)

end program LBM_Cavity

lbm_cavity.cuf

Page 56: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

プログラムのコンパイル

2016/1/13GPGPU講習会56

コンパイラにはpgfortranを利用

pgf90でも可能

リンクせずにオブジェクトファイルを生成

$ pgf90 ‐c module_SimulationParameter.f90 $ pgf90 ‐Mcuda=cc20 ‐c module_D2Q9Model.cuf $ pgf90 ‐Mcuda=cc20 ‐c lbm_cavity.cuf

オブジェクトファイルをリンクして実行ファイルを生成

$ pgf90 ‐Mcuda=cc20 ‐o lbm_cavity *.o

Page 57: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

1スレッド実装の実行結果

2016/1/13GPGPU講習会57

CPU版と同じ結果は得られる

実行が遅すぎて使い物にならない

実行時間

512× 512で約 3s/step 1024×1024で約10s/step 2048×2048で約50s/step

GPUは並列計算しないと遅い

どのような計算でも速くなるわけではない

Page 58: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

1スレッドが1格子点(9粒子)を計算

2016/1/13GPGPU講習会58

1スレッド実装からの変更点

1.複数スレッドでのカーネル呼出

2.カーネルの内容

1.i,jに関するdoループがあると1スレッドが複数の点を計算してしまう

2.スレッド番号と格子点番号の対応付け

3.境界条件を処理するカーネルの分割

U

03 147 8

26 503 147 8

26 5

03 147 8

26 503 147 8

26 5

0326

03 126 5

03 126 5

0 12 5

0 14 8

2 5

0 14 8

2 5

0 14 8

2 503 147 8

26 503 147 8

26 5

0347

26

0347

26

0347

2637

6

37

6

37

6

37

6

47 847 84 8 47

18

5

18

5

18

15

8

5

スレッド13 スレッド14 スレッド15 スレッド16

スレッド9 スレッド10 スレッド11 スレッド12

スレッド5 スレッド6 スレッド7 スレッド8

スレッド1 スレッド2 スレッド3 スレッド4

Page 59: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

1スレッドが1格子点(9粒子)を計算

2016/1/13GPGPU講習会59

1スレッド実装からの変更点

Stream Stepの実装

一時的な配列が必要

スレッド33が必ず先に処理をするか,スレッド32,33が全く同時に処理を行うことが保証されている必要がある

CUDAでは,あるまとまった数のスレッド群が協調して動作

スレッド群を切替ながら処理を実行

一時的な配列を利用

f(Right,33,1)=f(Right,32,1) f(Right,34,1)=f(Right,33,1)スレッド32 スレッド33

f_new(Right,33,1)=f(Right,32,1) f_new(Right,34,1)=f(Right,33,1)スレッド32 スレッド33

Page 60: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

GPU実行用パラメータ(新規追加)

2016/1/13GPGPU講習会60

module GPUParameteruse cudaforuse SimulationParameter,only:Nx,Nyimplicit none

!1ブロックあたりのスレッド数の基準値integer,parameter :: num_Thread = 64

!境界条件以外のカーネルの並列度integer,parameter :: Thread_x = min(Nx,num_Thread)integer,parameter :: Thread_y = 1integer,parameter ::  Block_x = Nx/Thread_xinteger,parameter ::  Block_y = Ny/Thread_ytype(dim3),parameter :: Thread = dim3(Thread_x, Thread_y, 1) !dim3型構造体を利用してtype(dim3),parameter :: Block  = dim3( Block_x,  Block_y, 1) !カーネルの並列度を指定

module_GPUParameter.cuf

source/gpu/naive/に置いています

Page 61: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

GPU実行用パラメータ(新規追加)

2016/1/13GPGPU講習会61

!x方向境界条件を処理するカーネルの並列度integer,parameter :: ThreadBCx_x = min(Nx,num_Thread)integer,parameter :: ThreadBCx_y = 1integer,parameter ::  BlockBCx_x = Nx/ThreadBCx_xinteger,parameter ::  BlockBCx_y = 1 !y方向のブロック数は1に固定type(dim3),parameter :: ThreadBCx = dim3(ThreadBCx_x, ThreadBCx_y, 1)type(dim3),parameter ::  BlockBCx = dim3( BlockBCx_x,  BlockBCx_y, 1)

!y方向境界条件を処理するカーネルの並列度integer,parameter :: ThreadBCy_x = 1integer,parameter :: ThreadBCy_y = min(Ny,num_Thread)integer,parameter ::  BlockBCy_x = 1 !x方向のブロック数は1に固定integer,parameter ::  BlockBCy_y = Ny/ThreadBCy_ytype(dim3),parameter :: ThreadBCy = dim3(ThreadBCy_x, ThreadBCy_y, 1)type(dim3),parameter ::  BlockBCy = dim3( BlockBCy_x,  BlockBCy_y, 1)

end module GPUParameter

module_GPUParameter.cuf

Page 62: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

初期マクロ量の設定

2016/1/13GPGPU講習会62

attributes(global) subroutine computeIntialMacroQuantities(velx,vely,dens)use SimulationParameterimplicit none

real(8),intent(inout),device :: velx(Nx,Ny)real(8),intent(inout),device :: vely(Nx,Ny)real(8),intent(inout),device :: dens(Nx,Ny)

integer :: i,j

i = (blockIdx%x‐1)*blockDim%x + threadIdx%x !スレッド番号と配列添字の対応付けj = (blockIdx%y‐1)*blockDim%y + threadIdx%y !

!1スレッドが1格子点を処理するのでi,jのdoループを削除velx(i,j) = 0d0vely(i,j) = 0d0dens(i,j) = 1d0

if (2<=i.and.i<=Nx‐1 .and. j==Ny) then !doループで格子点(i,j)を制御できないので,if文で制御velx(i,j) = Uwall

end ifend subroutine computeIntialMacroQuantities

module_D2Q9Model.cuf

Page 63: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会63

attributes(global) subroutine computeMacroQuantities(f,velx,vely,dens,ConvVelx,ConvVely)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f(First:Last,1:Nx,1:Ny)real(8),intent(inout),device :: velx(1:Nx,1:Ny)real(8),intent(inout),device :: vely(1:Nx,1:Ny)real(8),intent(inout),device :: dens(1:Nx,1:Ny)integer,intent(in)   ,device :: ConvVelx(First:Last)integer,intent(in)   ,device :: ConvVely(First:Last)integer :: i,jreal(8) :: f_boundary, f_exterior

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

dens(i,j) =  f(Center   ,i,j)+f(Right    ,i,j)+f(Up       ,i,j)&+f(Left     ,i,j)+f(Down     ,i,j)+f(UpRight ,i,j)&+f(UpLeft ,i,j)+f(DownLeft ,i,j)+f(DownRight,i,j)

if (2<=i.and.i<=Nx‐1 .and. j==Ny) thenf_boundary = f(Center,i,j)+f(  Right,i,j)+f(  Left,i,j)f_exterior = f(Up    ,i,j)+f(UpRight,i,j)+f(UpLeft,i,j)dens(i,j) = f_boundary + 2d0*f_exterior

end if

module_D2Q9Model.cuf

Page 64: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会64

if (2<=i.and.i<=Nx‐1 .and. 2<=j.and.j<=Ny‐1) thenvelx(i,j) = ( f(Center   ,i,j)*ConvVelx(Center   )&

+f(Right    ,i,j)*ConvVelx(Right    )&+f(Up       ,i,j)*ConvVelx(Up       )&+f(Left     ,i,j)*ConvVelx(Left     )&+f(Down     ,i,j)*ConvVelx(Down     )&+f(UpRight ,i,j)*ConvVelx(UpRight )&+f(UpLeft ,i,j)*ConvVelx(UpLeft )&+f(DownLeft ,i,j)*ConvVelx(DownLeft )&+f(DownRight,i,j)*ConvVelx(DownRight))/dens(i,j)

vely(i,j) = ( f(Center   ,i,j)*ConvVely(Center   )&+f(Right    ,i,j)*ConvVely(Right    )&+f(Up       ,i,j)*ConvVely(Up       )&+f(Left     ,i,j)*ConvVely(Left     )&+f(Down     ,i,j)*ConvVely(Down     )&+f(UpRight ,i,j)*ConvVely(UpRight )&+f(UpLeft ,i,j)*ConvVely(UpLeft )&+f(DownLeft ,i,j)*ConvVely(DownLeft )&+f(DownRight,i,j)*ConvVely(DownRight))/dens(i,j)

end ifend subroutine computeMacroQuantities

module_D2Q9Model.cuf

Page 65: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数

2016/1/13GPGPU講習会65

attributes(global) &subroutine computeLocalEquilibriumFunction(f_eq,velx,vely,dens,ConvVelx,ConvVely,Weight)

use SimulationParameterimplicit nonereal(8),intent(inout),device :: f_eq(First:Last,1:Nx,1:Ny)real(8),intent(in)   ,device :: velx(1:Nx,1:Ny)real(8),intent(in)   ,device :: vely(1:Nx,1:Ny)real(8),intent(in)   ,device :: dens(1:Nx,1:Ny)integer,intent(in)   ,device :: ConvVelx(First:Last)integer,intent(in)   ,device :: ConvVely(First:Last)real(8),intent(in)   ,device :: Weight(First:Last)real(8) :: u,v,conv_velo,velo_squareinteger :: i,j,direction

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

module_D2Q9Model.cuf

Page 66: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数

2016/1/13GPGPU講習会66

u = velx(i,j)v = vely(i,j)velo_square = u*u + v*v!1スレッドが9個の粒子を計算するので,粒子番号に関するdoループは存在do direction = First,Last

conv_velo =  u*ConvVelx(direction) + v*ConvVely(direction)f_eq(direction,i,j) = Weight(direction)*dens(i,j)&

*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)end do

end subroutine computeLocalEquilibriumFunction

module_D2Q9Model.cuf

Page 67: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Collision Step

2016/1/13GPGPU講習会67

attributes(global) subroutine collide(f,f_eq)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f   (First:Last,1:Nx,1:Ny)real(8),intent(in)   ,device :: f_eq(First:Last,1:Nx,1:Ny)integer :: i,j,direction

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

f(:,i,j) = f(:,i,j) + (f_eq(:,i,j)‐f(:,i,j))/RelaxTimeend subroutine collide

module_D2Q9Model.cuf

Page 68: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会68

attributes(global) subroutine stream(f,f_new)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f    (First:Last,1:Nx,1:Ny)real(8),intent(inout),device :: f_new(First:Last,1:Nx,1:Ny)integer :: i,j

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

f_new(Center,i,j) = f(Center,i,j) !一時配列f_newを利用if (1<=i .and. i<=Nx‐1) then

f_new(Right,i+1,j) = f(Right,i,j)end ifif (1<=j .and. j<=Ny‐1) then

f_new(Up,i,j+1) = f(Up,i,j)end ifif (2<=i .and. i<=Nx) then

f_new(Left,i‐1,j) = f(Left,i,j)end ifif (2<=j .and. j<=Ny) then

f_new(Down,i,j‐1) = f(Down,i,j)end if

module_D2Q9Model.cuf

Page 69: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会69

if (1<=i .and. i<=Nx‐1 .and. 1<=j .and. j<=Ny‐1) thenf_new(UpRight,i+1,j+1) = f(UpRight,i,j)

end ifif (2<=i .and. i<=Nx .and. 1<=j .and. j<=Ny‐1) then

f_new(UpLeft,i‐1,j+1) = f(UpLeft,i,j)end ifif (2<=i .and. i<=Nx .and. 2<=j .and. j<=Ny) then

f_new(DownLeft ,i‐1,j‐1) = f(DownLeft ,i,j)end ifif (1<=i .and. i<=Nx‐1 .and. 2<=j .and. j<=Ny) then

f_new(DownRight,i+1,j‐1) = f(DownRight,i,j)end if

end subroutine stream

module_D2Q9Model.cuf

Page 70: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

x方向境界条件

2016/1/13GPGPU講習会70

1行分のスレッドを起動し,1スレッドが2点の境界値を計算

ブロックは1行分あればよい

y方向ブロック数は1に固定

x方向はスレッド番号と配列要素の対応付けが可能

i = (blockIdx%x‐1)*blockDim%x+ threadIdx%x

y方向は数値を直接指定

j=1

f(:,:,:)

i

jブロック

Page 71: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

x方向境界条件

2016/1/13GPGPU講習会71

1行分のスレッドを起動し,1スレッドが2点の境界値を計算

ブロックは1行分あればよい

y方向ブロック数は1に固定

x方向はスレッド番号と配列要素の対応付けが可能

i = (blockIdx%x‐1)*blockDim%x+ threadIdx%x

y方向は数値を直接指定

j=Ny

i

j

f(:,:,:)

ブロック

Page 72: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

x方向境界条件

2016/1/13GPGPU講習会72

attributes(global) subroutine imposeBoundayCondition_x(f,Opposite)use SimulationParameterimplicit none

real(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)integer,intent(in)   ,device :: Opposite(First:Last)

integer :: ireal(8) :: dens_wallreal(8) :: f_boundary, f_exterior

i = (blockIdx%x‐1)*blockDim%x + threadIdx%x

!bounce back on south boundaryf(Up     ,i,1)=f(Opposite(Up     ),i,1)f(UpRight,i,1)=f(Opposite(UpRight),i,1)f(UpLeft ,i,1)=f(Opposite(UpLeft ),i,1)

module_D2Q9Model.cuf

Page 73: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

x方向境界条件

2016/1/13GPGPU講習会73

!moving wall, north boundaryif (2<=i.and.i<=Nx‐1) then

f_boundary = f(Center,i,Ny)+f(  Right,i,Ny)+f(  Left,i,Ny)f_exterior = f(Up    ,i,Ny)+f(UpRight,i,Ny)+f(UpLeft,i,Ny)dens_wall = f_boundary + 2d0*f_exteriorf(Down     ,i,Ny)=f(Opposite(Down     ),i,Ny)f(DownRight,i,Ny)=f(Opposite(DownRight),i,Ny) + dens_wall*Uwall/6.0f(DownLeft ,i,Ny)=f(Opposite(DownLeft ),i,Ny) ‐ dens_wall*Uwall/6.0

end if

end subroutine imposeBoundayCondition_x

module_D2Q9Model.cuf

Page 74: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

y方向境界条件

2016/1/13GPGPU講習会74

1列分のスレッドを起動し,1スレッドが2点の境界値を計算

ブロックは1列分あればよい

x方向ブロック数は1に固定

y方向はスレッド番号と配列要素の対応付けが可能

j = (blockIdx%y‐1)*blockDim%y+ threadIdx%y

x方向は数値を直接指定

i=1

i

j

f(:,:,:)

ブロック

Page 75: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

y方向境界条件

2016/1/13GPGPU講習会75

1列分のスレッドを起動し,1スレッドが2点の境界値を計算

ブロックは1列分あればよい

x方向ブロック数は1に固定

y方向はスレッド番号と配列要素の対応付けが可能

j = (blockIdx%y‐1)*blockDim%y+ threadIdx%y

x方向は数値を直接指定

i=Nx

i

j

f(:,:,:)

ブロック

Page 76: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

y方向境界条件

2016/1/13GPGPU講習会76

attributes(global) subroutine imposeBoundayCondition_y(f,Opposite)use SimulationParameterimplicit none

real(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)integer,intent(in)   ,device :: Opposite(First:Last)

integer :: j

j = (blockIdx%y‐1)*blockDim%y + threadIdx%y

!bounce back on west boundaryf(    Right, 1,j) = f(Opposite(    Right), 1,j)f(  UpRight, 1,j) = f(Opposite(  UpRight), 1,j)f(DownRight, 1,j) = f(Opposite(DownRight), 1,j)!bounce back on east boundaryf(    Left ,Nx,j) = f(Opposite(    Left ),Nx,j)f(DownLeft ,Nx,j) = f(Opposite(DownLeft ),Nx,j)f(  UpLeft ,Nx,j) = f(Opposite(  UpLeft ),Nx,j)

end subroutine imposeBoundayCondition_y

module_D2Q9Model.cuf

Page 77: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会77

program LBM_Cavityuse cudaforuse SimulationParameteruse D2Q9Modeluse GPUParameterimplicit none

real(8),allocatable,device ::  velx(:,:)real(8),allocatable,device ::  vely(:,:)real(8),allocatable,device ::  dens(:,:)

real(8),allocatable,device :: f    (:,:,:)real(8),allocatable,device :: f_eq (:,:,:)real(8),allocatable,device :: f_new(:,:,:) !一時配列

real(8),allocatable,device :: dev_Weight(:)integer,allocatable,device :: dev_ConvVelx(:)integer,allocatable,device :: dev_ConvVely(:)integer,allocatable,device :: dev_Opposite(:)

integer :: n,stat

lbm_cavity.cuf

Page 78: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会78

allocate( velx(1:Nx,1:Ny))allocate( vely(1:Nx,1:Ny))allocate( dens(1:Nx,1:Ny))

allocate(f    (First:Last,1:Nx,1:Ny));f    =0d0allocate(f_eq (First:Last,1:Nx,1:Ny));f_eq =0d0allocate(f_new(First:Last,1:Nx,1:Ny));f_new=0d0

allocate(dev_Weight(First:Last));  dev_Weight =Weightallocate(dev_ConvVelx(First:Last));dev_ConvVelx=ConvVelxallocate(dev_ConvVely(First:Last));dev_ConvVely=ConvVelyallocate(dev_Opposite(First:Last));dev_Opposite=Opposite

lbm_cavity.cuf

Page 79: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会79

call computeIntialMacroQuantities<<<Block,Thread>>>(velx,vely,dens)do n=1,Nt

call computeLocalEquilibriumFunction<<<Block,Thread>>>(f_eq,velx,vely,dens,dev_ConvVelx,dev_ConvVely,dev_Weight)

call collide<<<Block,Thread>>>(f,f_eq)call stream<<<Block,Thread>>>(f,f_new)call imposeBoundayCondition_x<<<BlockBCx,ThreadBCx>>>(f_new,dev_Opposite)call imposeBoundayCondition_y<<<BlockBCy,ThreadBCy>>>(f_new,dev_Opposite)call computeMacroQuantities<<<Block,Thread>>>

(f_new,velx,vely,dens,dev_ConvVelx,dev_ConvVely)f = f_new !一時配列f_newの値をfにコピー(同期実行されるのでcudaThreadSynchronizeは削除)

end dodeallocate(f    )deallocate(f_eq )deallocate(f_new)deallocate(velx )deallocate(vely )deallocate(dens )deallocate(dev_Weight)deallocate(dev_ConvVelx)deallocate(dev_ConvVely)deallocate(dev_Opposite)

end program LBM_Cavitylbm_cavity.cuf

Page 80: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

実行結果(1スレッド1格子点)

2016/1/13GPGPU講習会80

実行時間(1ブロックあたりのスレッド数が64のとき)

512× 512 約 9ms/step 1024×1024 約 35ms/step 2048×2048 約150ms/step 単純な実装でもCPUより6倍程度高速化

格子点数実行時間[ms] 高速化率

(CPU/GPU)CPU GPU

512× 512 52 9 5.8

1024×1024 214 35 6.1

2048×2048 900 150 6

Page 81: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

1ブロックあたりのスレッド数の違いによる実行時間の変化

2016/1/13GPGPU講習会81

いずれの格子点数でも,1ブロックあたりのスレッド数が64の時が も高速 以降の 適化でも64スレッド/ブロックを使用

実行

時間

[s/

step

]実行

時間

[s/

step

]

Number of Threads/Block

512×512 1024×1024

2048×2048

Number of Threads/Block

Page 82: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

パラメータを保持するメモリの選択

2016/1/13GPGPU講習会82

重み係数,移流速度を保持するメモリを変更

コンスタントメモリを利用

引数で渡さなくなるのでカーネルが単純化

全スレッドが同じデータにアクセスするので,コンスタントキャッシュにより高速化が期待

コンスタントメモリ

GPUからは読込専用のオフチップ(GPUのチップ外の)メモリ

読込自体は高速ではない

複数のスレッドが同じデータにアクセスすると,コンスタントキャッシュが利用される

グローバル領域で宣言

Page 83: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

D2Q9モデルのパラメータ

2016/1/13GPGPU講習会83

!パラメータを定義

:

!コンスタントメモリはconstant属性を付けて宣言real(8),constant :: cWeight(First:Last)integer,constant :: cConvVelx(First:Last)integer,constant :: cConvVely(First:Last)integer,constant :: cOpposite(First:Last)

:

module_D2Q9Model.cuf

source/gpu/constant/に置いています

Page 84: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会84

attributes(global) subroutine computeMacroQuantities(f,velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f(First:Last,1:Nx,1:Ny)real(8),intent(inout),device :: velx(1:Nx,1:Ny)real(8),intent(inout),device :: vely(1:Nx,1:Ny)real(8),intent(inout),device :: dens(1:Nx,1:Ny)integer :: i,jreal(8) :: f_boundary, f_exterior

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

dens(i,j) =  f(Center   ,i,j)+f(Right    ,i,j)+f(Up       ,i,j)&+f(Left     ,i,j)+f(Down     ,i,j)+f(UpRight ,i,j)&+f(UpLeft ,i,j)+f(DownLeft ,i,j)+f(DownRight,i,j)

if (2<=i.and.i<=Nx‐1 .and. j==Ny) thenf_boundary = f(Center,i,j)+f(  Right,i,j)+f(  Left,i,j)f_exterior = f(Up    ,i,j)+f(UpRight,i,j)+f(UpLeft,i,j)dens(i,j) = f_boundary + 2d0*f_exterior

end if

module_D2Q9Model.cuf

Page 85: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会85

if (2<=i.and.i<=Nx‐1 .and. 2<=j.and.j<=Ny‐1) thenvelx(i,j) = ( f(Center   ,i,j)*cConvVelx(Center   )&

+f(Right    ,i,j)*cConvVelx(Right    )&+f(Up       ,i,j)*cConvVelx(Up       )&+f(Left     ,i,j)*cConvVelx(Left     )&+f(Down     ,i,j)*cConvVelx(Down     )&+f(UpRight ,i,j)*cConvVelx(UpRight )&+f(UpLeft ,i,j)*cConvVelx(UpLeft )&+f(DownLeft ,i,j)*cConvVelx(DownLeft )&+f(DownRight,i,j)*cConvVelx(DownRight))/dens(i,j)

vely(i,j) = ( f(Center   ,i,j)*cConvVely(Center   )&+f(Right    ,i,j)*cConvVely(Right    )&+f(Up       ,i,j)*cConvVely(Up       )&+f(Left     ,i,j)*cConvVely(Left     )&+f(Down     ,i,j)*cConvVely(Down     )&+f(UpRight ,i,j)*cConvVely(UpRight )&+f(UpLeft ,i,j)*cConvVely(UpLeft )&+f(DownLeft ,i,j)*cConvVely(DownLeft )&+f(DownRight,i,j)*cConvVely(DownRight))/dens(i,j)

end ifend subroutine computeMacroQuantities

module_D2Q9Model.cuf

Page 86: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数

2016/1/13GPGPU講習会86

attributes(global) subroutine computeLocalEquilibriumFunction(f_eq,velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f_eq(First:Last,1:Nx,1:Ny)real(8),intent(in)   ,device :: velx(1:Nx,1:Ny)real(8),intent(in)   ,device :: vely(1:Nx,1:Ny)real(8),intent(in)   ,device :: dens(1:Nx,1:Ny)real(8) :: u,v,conv_velo,velo_squareinteger :: i,j,directioni = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

u = velx(i,j)v = vely(i,j)velo_square = u*u + v*vdo direction = First,Last

conv_velo =  u*cConvVelx(direction) + v*cConvVely(direction)f_eq(direction,i,j) = cWeight(direction)*dens(i,j)&

*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)end do

end subroutine computeLocalEquilibriumFunction

module_D2Q9Model.cuf

Page 87: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

x方向境界条件

2016/1/13GPGPU講習会87

attributes(global) subroutine imposeBoundayCondition_x(f)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)real(8) :: dens_wallreal(8) :: f_boundary, f_exteriorinteger :: ii = (blockIdx%x‐1)*blockDim%x + threadIdx%x

!bounce back on south boundaryf(Up     ,i,1)=f(cOpposite(Up     ),i,1)f(UpRight,i,1)=f(cOpposite(UpRight),i,1)f(UpLeft ,i,1)=f(cOpposite(UpLeft ),i,1)!moving wall, north boundaryif (2<=i.and.i<=Nx‐1) then

f_boundary = f(Center,i,Ny)+f(  Right,i,Ny)+f(  Left,i,Ny)f_exterior = f(Up    ,i,Ny)+f(UpRight,i,Ny)+f(UpLeft,i,Ny)dens_wall = f_boundary + 2d0*f_exteriorf(Down     ,i,Ny)=f(cOpposite(Down     ),i,Ny)f(DownRight,i,Ny)=f(cOpposite(DownRight),i,Ny) + dens_wall*Uwall/6.0f(DownLeft ,i,Ny)=f(cOpposite(DownLeft ),i,Ny) ‐ dens_wall*Uwall/6.0

end ifend subroutine imposeBoundayCondition_x

module_D2Q9Model.cuf

Page 88: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

y方向境界条件

2016/1/13GPGPU講習会88

attributes(global) subroutine imposeBoundayCondition_y(f)use SimulationParameterimplicit none

real(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)

integer :: j

j = (blockIdx%y‐1)*blockDim%y + threadIdx%y

!bounce back on west boundaryf(    Right, 1,j) = f(cOpposite(    Right), 1,j)f(  UpRight, 1,j) = f(cOpposite(  UpRight), 1,j)f(DownRight, 1,j) = f(cOpposite(DownRight), 1,j)!bounce back on east boundaryf(    Left ,Nx,j) = f(cOpposite(    Left ),Nx,j)f(DownLeft ,Nx,j) = f(cOpposite(DownLeft ),Nx,j)f(  UpLeft ,Nx,j) = f(cOpposite(  UpLeft ),Nx,j)

end subroutine imposeBoundayCondition_y

module_D2Q9Model.cuf

Page 89: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会89

program LBM_Cavityuse cudaforuse SimulationParameteruse D2Q9Modeluse GPUParameterimplicit none

real(8),allocatable,device ::  velx(:,:)real(8),allocatable,device ::  vely(:,:)real(8),allocatable,device ::  dens(:,:)

real(8),allocatable,device :: f    (:,:,:)real(8),allocatable,device :: f_eq (:,:,:)real(8),allocatable,device :: f_new(:,:,:)

integer :: n,stat

lbm_cavity.cuf

Page 90: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会90

allocate( velx(1:Nx,1:Ny))allocate( vely(1:Nx,1:Ny))allocate( dens(1:Nx,1:Ny))

allocate(f    (First:Last,1:Nx,1:Ny));f    =0d0allocate(f_eq (First:Last,1:Nx,1:Ny));f_eq =0d0allocate(f_new(First:Last,1:Nx,1:Ny));f_new=0d0

!CPUのメモリからコンスタントメモリへ転送!メモリのallocateは不要cWeight =WeightcConvVelx=ConvVelxcConvVely=ConvVelycOpposite=Opposite

lbm_cavity.cuf

Page 91: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会91

call computeIntialMacroQuantities<<<Block,Thread>>>(velx,vely,dens)do n=1,Nt

call computeLocalEquilibriumFunction<<<Block,Thread>>>(f_eq,velx,vely,dens)call collide<<<Block,Thread>>>(f,f_eq)call stream<<<Block,Thread>>>(f,f_new)call imposeBoundayCondition_x<<<BlockBCx,ThreadBCx>>>(f_new)call imposeBoundayCondition_y<<<BlockBCy,ThreadBCy>>>(f_new)call computeMacroQuantities<<<Block,Thread>>>(f_new,velx,vely,dens)f = f_new

end do

deallocate(f    )deallocate(f_eq )deallocate(f_new)deallocate(velx )deallocate(vely )deallocate(dens )

end program LBM_Cavity

lbm_cavity.cuf

Page 92: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

実行結果(コンスタントメモリ利用)

2016/1/13GPGPU講習会92

実行時間(2048×2048) 基準となる実装(Naïve)と比較してわずかに高速化

実行

時間

[s/

step

]

実装

18,632 15,098マクロ量の計算が有意に高速化

146,633 142,500*CPUの実行時間900,000s/step

Page 93: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

カーネル融合(フュージョン)

2016/1/13GPGPU講習会93

局所平衡分布関数の計算とCollision Stepの融合

局所平衡分布関数f_eqはCollision Stepでしか利用されていない

局所平衡分布関数の計算とCollision Stepのカーネルを合体すると

変数f_eqが不要

f_eqへの書込とf_eqからの読込が不要

Page 94: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数と衝突項の計算

2016/1/13GPGPU講習会94

attributes(global) &subroutine computeLocalEquilibriumFunctionAndCollision(f,velx,vely,dens)

use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(First:Last,1:Nx,1:Ny)real(8),intent(in)   ,device :: velx(1:Nx,1:Ny)real(8),intent(in)   ,device :: vely(1:Nx,1:Ny)real(8),intent(in)   ,device :: dens(1:Nx,1:Ny)real(8) :: u,v,conv_velo,velo_square,f_eq !f_eqをレジスタに確保integer :: i,j,directioni = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%yu = velx(i,j)v = vely(i,j)velo_square = u*u + v*vdo direction = First,Last

conv_velo =  u*cConvVelx(direction)&+ v*cConvVely(direction)

f_eq = cWeight(direction)*dens(i,j)& !f_eqを計算した直後に衝突項を計算*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)

f(direction,i,j) = f(direction,i,j) + (f_eq‐f(direction,i,j))/RelaxTimeend do

end subroutine computeLocalEquilibriumFunctionAndCollision

module_D2Q9Model.cuf

source/gpu/fusion/に置いています

Page 95: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会95

program LBM_Cavityuse cudaforuse SimulationParameteruse D2Q9Modeluse GPUParameterimplicit nonereal(8),allocatable,device ::  velx(:,:)real(8),allocatable,device ::  vely(:,:)real(8),allocatable,device ::  dens(:,:)real(8),allocatable,device :: f    (:,:,:)real(8),allocatable,device :: f_new(:,:,:) !f_eqを消去integer :: n,stat

allocate( velx(1:Nx,1:Ny))allocate( vely(1:Nx,1:Ny))allocate( dens(1:Nx,1:Ny))allocate(f    (1:Nx,1:Ny,First:Last));f    =0d0allocate(f_new(1:Nx,1:Ny,First:Last));f_new=0d0cWeight =WeightcConvVelx=ConvVelxcConvVely=ConvVelycOpposite=Opposite

lbm_cavity.cuf

Page 96: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会96

call computeIntialMacroQuantities<<<Block,Thread>>>(velx,vely,dens)do n=1,Nt

call computeLocalEquilibriumFunctionAndCollision<<<Block,Thread>>>(f,velx,vely,dens)

call stream<<<Block,Thread>>>(f,f_new)call imposeBoundayCondition_x<<<BlockBCx,ThreadBCx>>>(f_new)call imposeBoundayCondition_y<<<BlockBCy,ThreadBCy>>>(f_new)call computeMacroQuantities<<<Block,Thread>>>(f_new,velx,vely,dens)f = f_new

end do

deallocate(f    )deallocate(f_new)deallocate(velx )deallocate(vely )deallocate(dens )

end program LBM_Cavity

lbm_cavity.cuf

Page 97: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

実行結果(カーネル融合)

2016/1/13GPGPU講習会97

実行時間(2048×2048) 局所平衡分布関数と衝突項の計算が著しく高速化

実行

時間

[s/

step

]

実装

83,610 17,712

76,474

146,633 142,500*CPUの実行時間900,000s/step

Page 98: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

配列構造の最適化

2016/1/13GPGPU講習会98

粒子の分布関数f(:,:,:) x, y座標,9個の粒子のデータを一括して取り扱う

3次元配列の構造

粒子×x座標×y座標

この並びはGPUにとって 適ではない

3次元配列の構造の変更

粒子(9個分)×x座標×y座標→x座標×y座標×粒子

Page 99: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

配列構造の最適化

2016/1/13GPGPU講習会99

GPUのメモリ(グローバルメモリ)の特徴

読み込みがある一定サイズでまとめて行われる

スレッド群が協調してメモリにアクセス

効率のよいアクセスには一定の条件がある

コアレスアクセス(Coalesce Access) データのサイズ (4,8,16バイトのいずれか)

アクセスする 初のアドレス (64か128バイトの倍数)

アドレスの隣接

スレッド群がアクセスするメモリのアドレスが,スレッド番号順に隣接

・・・A128 A132 A136

スレッド

1スレッド

3スレッド

2スレッド

i‐1スレッド

i

グローバルメモリ

Page 100: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

配列構造の最適化

2016/1/13GPGPU講習会100

今までの配列構造とスレッド群のメモリアクセス

pij

f(p,i,j) Fortranのメモリはp,i,jの順に連続

f(1,1,1),f(2,1,1),f(3,1,1)の順に連続

i,j方向を並列化

1スレッドが粒子に逐次アクセス

各スレッドは粒子9個×8バイト

の間隔でグローバルメモリにアクセス

コアレスアクセスできていない

スレッド群

Page 101: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

配列構造の最適化

2016/1/13GPGPU講習会101

適化した配列構造とスレッド群のメモリアクセス

配列構造をx座標×y座標×粒子に変更

i,j方向を並列化

1スレッドが粒子に逐次アクセス

ijp

f(i,j,p)

各スレッドは連続したアドレスにアクセス

コアレスアクセス

1スレッドは粒子9個×x方向格子点数×y方向格子点数×8バイトの間隔でグローバルメモリにアクセス

スレッド群

Page 102: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数の計算と衝突項の計算

2016/1/13GPGPU講習会102

attributes(global) &subroutine computeLocalEquilibriumFunctionAndCollision(f,velx,vely,dens)

use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(1:Nx,1:Ny,First:Last)real(8),intent(in)   ,device :: velx(1:Nx,1:Ny)real(8),intent(in)   ,device :: vely(1:Nx,1:Ny)real(8),intent(in)   ,device :: dens(1:Nx,1:Ny)real(8) :: u,v,conv_velo,velo_square,f_eqinteger :: i,j,directioni = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

u = velx(i,j)v = vely(i,j)velo_square = u*u + v*vdo direction = First,Last

conv_velo =  u*cConvVelx(direction) + v*cConvVely(direction)f_eq = cWeight(direction)*dens(i,j)&

*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)f(i,j,direction) = f(i,j,direction) + (f_eq‐f(i,j,direction))/RelaxTime

end doend subroutine computeLocalEquilibriumFunctionAndCollision

module_D2Q9Model.cuf

source/gpu/memory_layout/に置いています

Page 103: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会103

attributes(global) subroutine computeMacroQuantities(f,velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f(1:Nx,1:Ny,First:Last)real(8),intent(inout),device :: velx(1:Nx,1:Ny)real(8),intent(inout),device :: vely(1:Nx,1:Ny)real(8),intent(inout),device :: dens(1:Nx,1:Ny)integer :: i,jreal(8) :: f_boundary, f_exterior

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

dens(i,j) =  f(i,j,Center )+f(i,j,Right )+f(i,j,Up )&+f(i,j,Left )+f(i,j,Down )+f(i,j,UpRight )&+f(i,j,UpLeft )+f(i,j,DownLeft )+f(i,j,DownRight)

if (2<=i.and.i<=Nx‐1 .and. j==Ny) thenf_boundary = f(i,j,Center)+f(i,j,  Right)+f(i,j,  Left)f_exterior = f(i,j,Up )+f(i,j,UpRight)+f(i,j,UpLeft)dens(i,j) = f_boundary + 2d0*f_exterior

end if

module_D2Q9Model.cuf

Page 104: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会104

if (2<=i.and.i<=Nx‐1 .and. 2<=j.and.j<=Ny‐1) thenvelx(i,j) = ( f(i,j,Center )*cConvVelx(Center   )&

+f(i,j,Right )*cConvVelx(Right    )&+f(i,j,Up )*cConvVelx(Up       )&+f(i,j,Left )*cConvVelx(Left     )&+f(i,j,Down )*cConvVelx(Down     )&+f(i,j,UpRight )*cConvVelx(UpRight )&+f(i,j,UpLeft )*cConvVelx(UpLeft )&+f(i,j,DownLeft )*cConvVelx(DownLeft )&+f(i,j,DownRight)*cConvVelx(DownRight))/dens(i,j)

vely(i,j) = ( f(i,j,Center )*cConvVely(Center   )&+f(i,j,Right )*cConvVely(Right    )&+f(i,j,Up )*cConvVely(Up       )&+f(i,j,Left )*cConvVely(Left     )&+f(i,j,Down )*cConvVely(Down     )&+f(i,j,UpRight )*cConvVely(UpRight )&+f(i,j,UpLeft )*cConvVely(UpLeft )&+f(i,j,DownLeft )*cConvVely(DownLeft )&+f(i,j,DownRight)*cConvVely(DownRight))/dens(i,j)

end ifend subroutine computeMacroQuantities

module_D2Q9Model.cuf

Page 105: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会105

attributes(global) subroutine stream(f,f_new)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f    (1:Nx,1:Ny,First:Last)real(8),intent(inout),device :: f_new(1:Nx,1:Ny,First:Last)integer :: i,j

i = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%yf_new(i,j,Center) = f(i,j,Center)if (1<=i .and. i<=Nx‐1) then

f_new(i+1,j,Right) = f(i,j,Right)end ifif (1<=j .and. j<=Ny‐1) then

f_new(i,j+1,Up) = f(i,j,Up)end ifif (2<=i .and. i<=Nx) then

f_new(i‐1,j,Left) = f(i,j,Left)end ifif (2<=j .and. j<=Ny) then

f_new(i,j‐1,Down) = f(i,j,Down)end if module_D2Q9Model.cuf

Page 106: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

Stream Step

2016/1/13GPGPU講習会106

if (1<=i .and. i<=Nx‐1 .and. 1<=j .and. j<=Ny‐1) thenf_new(i+1,j+1,UpRight) = f(i,j,UpRight)

end ifif (2<=i .and. i<=Nx .and. 1<=j .and. j<=Ny‐1) then

f_new(i‐1,j+1,UpLeft) = f(i,j,UpLeft)end ifif (2<=i .and. i<=Nx .and. 2<=j .and. j<=Ny) then

f_new(i‐1,j‐1,DownLeft) = f(i,j,DownLeft)end ifif (1<=i .and. i<=Nx‐1 .and. 2<=j .and. j<=Ny) then

f_new(i+1,j‐1,DownRight) = f(i,j,DownRight)end if

end subroutine stream

module_D2Q9Model.cuf

Page 107: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会107

attributes(global) subroutine imposeBoundayCondition_x(f)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(1:Nx,1:Ny,First:Last)integer :: ireal(8) :: dens_wallreal(8) :: f_boundary, f_exteriori = (blockIdx%x‐1)*blockDim%x + threadIdx%x

!bounce back on south boundaryf(i,1,Up     )=f(i,1,cOpposite(Up     ))f(i,1,UpRight)=f(i,1,cOpposite(UpRight))f(i,1,UpLeft )=f(i,1,cOpposite(UpLeft ))!moving wall, north boundaryif (2<=i.and.i<=Nx‐1) then

f_boundary = f(i,Ny,Center)+f(i,Ny,  Right)+f(i,Ny,  Left)f_exterior = f(i,Ny,Up )+f(i,Ny,UpRight)+f(i,Ny,UpLeft)dens_wall = f_boundary + 2d0*f_exteriorf(i,Ny,Down )=f(i,Ny,cOpposite(Down     ))f(i,Ny,DownRight)=f(i,Ny,cOpposite(DownRight)) + dens_wall*Uwall/6.0f(i,Ny,DownLeft )=f(i,Ny,cOpposite(DownLeft )) ‐ dens_wall*Uwall/6.0

end ifend subroutine imposeBoundayCondition_x

module_D2Q9Model.cuf

Page 108: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

境界条件

2016/1/13GPGPU講習会108

attributes(global) subroutine imposeBoundayCondition_y(f)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(1:Nx,1:Ny,First:Last)integer :: jj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

!bounce back on west boundaryf( 1,j,    Right) = f( 1,j,cOpposite(    Right))f( 1,j,  UpRight) = f( 1,j,cOpposite(  UpRight))f( 1,j,DownRight) = f( 1,j,cOpposite(DownRight))!bounce back on east boundaryf(Nx,j,    Left ) = f(Nx,j,cOpposite(    Left ))f(Nx,j,DownLeft ) = f(Nx,j,cOpposite(DownLeft ))f(Nx,j,  UpLeft ) = f(Nx,j,cOpposite(  UpLeft ))

end subroutine imposeBoundayCondition_y

module_D2Q9Model.cuf

Page 109: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会109

program LBM_Cavityuse cudaforuse SimulationParameteruse D2Q9Modeluse GPUParameterimplicit nonereal(8),allocatable,device ::  velx(:,:)real(8),allocatable,device ::  vely(:,:)real(8),allocatable,device ::  dens(:,:)real(8),allocatable,device :: f    (:,:,:)real(8),allocatable,device :: f_new(:,:,:)integer :: n,stat

allocate( velx(1:Nx,1:Ny))allocate( vely(1:Nx,1:Ny))allocate( dens(1:Nx,1:Ny))allocate(f    (1:Nx,1:Ny,First:Last));f    =0d0allocate(f_new(1:Nx,1:Ny,First:Last));f_new=0d0cWeight =WeightcConvVelx=ConvVelxcConvVely=ConvVelycOpposite=Opposite

lbm_cavity.cuf

Page 110: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

メインルーチン

2016/1/13GPGPU講習会110

call computeIntialMacroQuantities<<<Block,Thread>>>(velx,vely,dens)do n=1,Nt

call computeLocalEquilibriumFunctionAndCollision<<<Block,Thread>>>(f,velx,vely,dens)

call stream<<<Block,Thread>>>(f,f_new)call imposeBoundayCondition_x<<<BlockBCx,ThreadBCx>>>(f_new)call imposeBoundayCondition_y<<<BlockBCy,ThreadBCy>>>(f_new)call computeMacroQuantities<<<Block,Thread>>>(f_new,velx,vely,dens)f = f_new

end do

deallocate(f    )deallocate(f_new)deallocate(velx )deallocate(vely )deallocate(dens )

end program LBM_Cavity

lbm_cavity.cuf

Page 111: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

実行結果(配列構造の最適化)

2016/1/13GPGPU講習会111

実行時間(2048×2048) 1/3程度に短縮

実行

時間

[s/

step

]

実装

21,577

*CPUの実行時間900,000s/step

76,474

146,633 142,500

Page 112: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

その他雑多な高速化

2016/1/13GPGPU講習会112

塵も積もれば山となる

著しい高速化は期待できないが,確実に高速化可能

GPUの得手不得手が分かる

除算を逆数のかけ算に変更

衝突項の計算に用いる緩和時間を,緩和時間の逆数の積に変更

レジスタによるマネージドキャッシュ

除算に用いる値をレジスタに格納して再利用

間接参照をやめてみる

Bounce Back境界条件で現れるOpposite()を消去してベタ書き

f(i,j,Down) = f(i,j,Oppsite(Down)) f(i,j,Down) = f(i,j,Up)

Page 113: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

計算パラメータ

2016/1/13GPGPU講習会113

!パラメータを設定

:real(8),parameter :: CoefRelax = 1d0/(3d0*KineticViscosity + 0.5d0)

module_SimulationParameter.cuf

source/gpu/misc/に置いています

Page 114: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会114

attributes(global) subroutine computeMacroQuantities(f,velx,vely,dens)use SimulationParameterimplicit nonereal(8),intent(in)   ,device :: f(1:Nx,1:Ny,First:Last)real(8),intent(inout),device :: velx(1:Nx,1:Ny)real(8),intent(inout),device :: vely(1:Nx,1:Ny)real(8),intent(inout),device :: dens(1:Nx,1:Ny)real(8) :: f_boundary, f_exterior, rhointeger :: i,ji = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

rho =  f(i,j,Center )+f(i,j,Right )+f(i,j,Up )&+f(i,j,Left )+f(i,j,Down )+f(i,j,UpRight )&+f(i,j,UpLeft )+f(i,j,DownLeft )+f(i,j,DownRight)

dens(i,j) = rho

if (2<=i.and.i<=Nx‐1 .and. j==Ny) thenf_boundary = f(i,j,Center)+f(i,j,  Right)+f(i,j,  Left)f_exterior = f(i,j,Up )+f(i,j,UpRight)+f(i,j,UpLeft)dens(i,j) = f_boundary + 2d0*f_exterior

end if

module_D2Q9Model.cuf

Page 115: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

マクロな密度と速度u1, u2の計算

2016/1/13GPGPU講習会115

if (2<=i.and.i<=Nx‐1 .and. 2<=j.and.j<=Ny‐1) thenvelx(i,j) = ( f(i,j,Center )*cConvVelx(Center   )&

+f(i,j,Right )*cConvVelx(Right    )&+f(i,j,Up )*cConvVelx(Up       )&+f(i,j,Left )*cConvVelx(Left     )&+f(i,j,Down )*cConvVelx(Down     )&+f(i,j,UpRight )*cConvVelx(UpRight )&+f(i,j,UpLeft )*cConvVelx(UpLeft )&+f(i,j,DownLeft )*cConvVelx(DownLeft )&+f(i,j,DownRight)*cConvVelx(DownRight))/rho

vely(i,j) = ( f(i,j,Center )*cConvVely(Center   )&+f(i,j,Right )*cConvVely(Right    )&+f(i,j,Up )*cConvVely(Up       )&+f(i,j,Left )*cConvVely(Left     )&+f(i,j,Down )*cConvVely(Down     )&+f(i,j,UpRight )*cConvVely(UpRight )&+f(i,j,UpLeft )*cConvVely(UpLeft )&+f(i,j,DownLeft )*cConvVely(DownLeft )&+f(i,j,DownRight)*cConvVely(DownRight))/rho

end ifend subroutine computeMacroQuantities

module_D2Q9Model.cuf

Page 116: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

局所平衡分布関数の計算と衝突項の計算

2016/1/13GPGPU講習会116

attributes(global) &subroutine computeLocalEquilibriumFunctionAndCollision(f,velx,vely,dens)

use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(1:Nx,1:Ny,First:Last)real(8),intent(in)   ,device :: velx(1:Nx,1:Ny)real(8),intent(in)   ,device :: vely(1:Nx,1:Ny)real(8),intent(in)   ,device :: dens(1:Nx,1:Ny)real(8) :: u,v,conv_velo,velo_square,f_eqinteger :: i,j,directioni = (blockIdx%x‐1)*blockDim%x + threadIdx%xj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

u = velx(i,j)v = vely(i,j)velo_square = u*u + v*vdo direction = First,Last

conv_velo =  u*cConvVelx(direction) + v*cConvVely(direction)f_eq = cWeight(direction)*dens(i,j)&

*(1d0 + 3d0*conv_velo + 4.5d0*conv_velo*conv_velo ‐ 1.5d0*velo_square)f(i,j,direction) = CoefRelax*f_eq + (1d0‐CoefRelax)*f(i,j,direction)

end doend subroutine computeLocalEquilibriumFunctionAndCollision

module_D2Q9Model.cuf

Page 117: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

x方向境界条件

2016/1/13GPGPU講習会117

attributes(global) subroutine imposeBoundayCondition_x(f)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(1:Nx,1:Ny,First:Last)real(8) :: dens_wallreal(8) :: f_boundary, f_exteriorinteger :: ii = (blockIdx%x‐1)*blockDim%x + threadIdx%x

!bounce back on south boundaryf(i,1,Up     )=f(i,1,Down     )f(i,1,UpRight)=f(i,1,DonwLeft )f(i,1,UpLeft )=f(i,1,DownRight)!moving wall, north boundaryif (2<=i.and.i<=Nx‐1) then

f_boundary = f(i,Ny,Center)+f(i,Ny,  Right)+f(i,Ny,  Left)f_exterior = f(i,Ny,Up )+f(i,Ny,UpRight)+f(i,Ny,UpLeft)dens_wall = f_boundary + 2d0*f_exteriorf(i,Ny,Down )=f(i,Ny,Up )f(i,Ny,DownRight)=f(i,Ny,UpLeft ) + dens_wall*Uwall/6.0f(i,Ny,DownLeft )=f(i,Ny,UpRight) ‐ dens_wall*Uwall/6.0

end ifend subroutine imposeBoundayCondition_x

module_D2Q9Model.cuf

Page 118: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

y方向境界条件

2016/1/13GPGPU講習会118

attributes(global) subroutine imposeBoundayCondition_y(f)use SimulationParameterimplicit nonereal(8),intent(inout),device :: f(1:Nx,1:Ny,First:Last)integer :: jj = (blockIdx%y‐1)*blockDim%y + threadIdx%y

!bounce back on west boundaryf( 1,j,    Right) = f( 1,j, Left)f( 1,j,  UpRight) = f( 1,j,DownLeft)f( 1,j,DownRight) = f( 1,j, UpLeft)!bounce back on east boundaryf(Nx,j,    Left ) = f(Nx,j, Right)f(Nx,j,DownLeft ) = f(Nx,j, UpRight)f(Nx,j,  UpLeft ) = f(Nx,j,DownRight)

end subroutine imposeBoundayCondition_y

module_D2Q9Model.cuf

Page 119: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

実行結果(雑多な最適化)

2016/1/13GPGPU講習会119

実行時間(2048×2048) カーネルによっては2,3%高速化

実行

時間

[s/

step

]

実装

7,030

5,584

6,884

5,406

21,248

除算の置き換えは有効

レジスタ利用は有効

21,577

76,474

146,633 142,500

間接参照の排除は有効性が不明(処理が軽すぎる)x方向境界条件 6s→ 5sy方向境界条件 36s→36s

*CPUの実行時間900,000s/step

Page 120: GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)

まとめ

2016/1/13GPGPU講習会120

格子ボルツマン法

並列化,GPU化に適した数値計算法

GPU化しない理由が無い

GPU実装といくつかの 適化を行った結果

単純なGPU実装から 適化により約7倍高速化

単純なCPU実装と比較して 大42倍高速化

他にも導入できる高速化は多数存在

局所平衡分布関数,衝突項とStream Stepを融合

共有メモリやレジスタの利用

テクスチャメモリの利用