Class | Alge_Solv |
In: |
alge_solv.f90
|
代数演算を用いて偏微分方程式を解くモジュール
Subroutine : | |||
nx : | integer, intent(in)
| ||
ny : | integer, intent(in)
| ||
dx : | real, intent(in)
| ||
dy : | real, intent(in)
| ||
rho(nx,ny) : | real, intent(in)
| ||
eps : | real, intent(in)
| ||
boundary : | integer, intent(in)
| ||
psi(nx,ny) : | real, intent(inout)
| ||
lambda : | real, intent(in)
| ||
bound_opt(nx,ny) : | real, intent(in), optional
|
ヤコビ法によるポアソン方程式の求積(開発中openmp)
subroutine Diff_2d_Jacobi(nx, ny, dx, dy, rho, eps, boundary, psi, lambda, bound_opt) ! ヤコビ法によるポアソン方程式の求積(開発中openmp) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 integer, intent(in) :: boundary ! 境界条件 real, intent(in) :: lambda ! 緩和係数 real, intent(in), optional :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: tmp, err, err_max ! boundary は 1 : 固定端境界, 2 : 自由端境界, 3 : 周期境界 ! rho =0 でラプラス方程式も求積可能. ! openmp によるスレッド並列が可能. ! ガウス・ザイデル法ではアルゴリズムの点から並列化が困難と思われたので, ! 並列計算によるポアソン方程式の求積が必要となるなら, ! ヤコビ法のものを使用されたい. psi = 0.0 select case (boundary) case(1) call fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) case(2) call free(nx,ny,dx,dy,eps,rho,psi) case(3) call period(nx,ny,dx,dy,eps,rho,psi) end select contains subroutine fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(in) :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 real :: tmp(nx,ny) ! ヤコビ法で解くために, イテレート後の値をプールする配列 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy !-- 固定端の設定 --- psi(1,:)=bound_opt(1,:) psi(nx,:)=bound_opt(nx,:) psi(:,1)=bound_opt(:,1) psi(:,nx)=bound_opt(:,nx) err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 tmp(i,j)=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) end do end do !$omp end parallel do !-- 誤差の計算 --- do j=2,ny-1 do i=2,nx-1 if(psi(i,j)==0.0)then err=abs(tmp(i,j)-psi(i,j))/abs(tmp(i,j)) else err=abs(tmp(i,j)-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if end do end do !$omp parallel do shared(tmp,psi) private(i,j) do j=2,ny-1 do i=2,nx-1 psi(i,j)=tmp(i,j) end do end do !$omp end parallel do end do end subroutine fix subroutine free(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 real :: tmp(nx,ny) ! ヤコビ法で解くために, イテレート後の値をプールする配列 integer :: i, j, k, l, m, n real :: delta delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 tmp(i,j)=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) end do end do !$omp end parallel do !-- 誤差の計算 --- do j=2,ny-1 do i=2,nx-1 if(psi(i,j)==0.0)then err=abs(tmp(i,j)-psi(i,j))/abs(tmp(i,j)) else err=abs(tmp(i,j)-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if end do end do !$omp parallel do shared(tmp,psi) private(i,j) do j=2,ny-1 do i=2,nx-1 psi(i,j)=tmp(i,j) end do end do !$omp end parallel do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,2) psi(1,2:ny-1)=psi(2,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,ny-1) psi(nx,2:ny-1)=psi(nx-1,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,2)+psi(2,1)) psi(1,ny)=0.5*(psi(1,ny-1)+psi(2,ny)) psi(nx,1)=0.5*(psi(nx,2)+psi(nx-1,1)) psi(nx,ny)=0.5*(psi(nx,ny-1)+psi(nx-1,ny)) end do end subroutine free subroutine period(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 real :: tmp(nx,ny) ! ヤコビ法で解くために, イテレート後の値をプールする配列 integer :: i, j, k, l, m, n real :: delta delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 tmp(i,j)=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) end do end do !$omp end parallel do !-- 誤差の計算 --- do j=2,ny-1 do i=2,nx-1 if(psi(i,j)==0.0)then err=abs(tmp(i,j)-psi(i,j))/abs(tmp(i,j)) else err=abs(tmp(i,j)-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if end do end do !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 psi(i,j)=tmp(i,j) end do end do !$omp end parallel do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,ny-1) psi(1,2:ny-1)=psi(nx-1,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,2) psi(nx,2:ny-1)=psi(2,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,ny-1)+psi(nx-1,1)) psi(1,ny)=0.5*(psi(1,2)+psi(nx-1,ny)) psi(nx,1)=0.5*(psi(nx,ny-1)+psi(2,1)) psi(nx,ny)=0.5*(psi(nx,2)+psi(2,ny)) end do end subroutine period end subroutine Diff_2d_Jacobi
Subroutine : | |||
nx : | integer, intent(in)
| ||
ny : | integer, intent(in)
| ||
dx : | real, intent(in)
| ||
dy : | real, intent(in)
| ||
rho(nx,ny) : | real, intent(in)
| ||
eps : | real, intent(in)
| ||
boundary : | integer, intent(in)
| ||
psi(nx,ny) : | real, intent(inout)
| ||
bound_opt(nx,ny) : | real, intent(in), optional
|
— ガウス=ザイデル法によるポアソン方程式の求積 —
subroutine Poisson_GauSei(nx, ny, dx, dy, rho, eps, boundary, psi, bound_opt) !-- ガウス=ザイデル法によるポアソン方程式の求積 --- implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 integer, intent(in) :: boundary ! 境界条件 real, intent(in), optional :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: tmp, err, err_max ! boundary は 1 : 固定端境界, 2 : 自由端境界, 3 : 周期境界 ! rho =0 でラプラス方程式も求積可能 psi = 0.0 select case (boundary) case(1) call fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) case(2) call free(nx,ny,dx,dy,eps,rho,psi) case(3) call period(nx,ny,dx,dy,eps,rho,psi) end select contains subroutine fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(in) :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy !-- 固定端の設定 --- psi(1,:)=bound_opt(1,:) psi(nx,:)=bound_opt(nx,:) psi(:,1)=bound_opt(:,1) psi(:,nx)=bound_opt(:,nx) err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 do j=2,ny-1 do i=2,nx-1 tmp=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) !-- 誤差の計算 --- if(psi(i,j)==0.0)then err=abs(tmp-psi(i,j))/abs(tmp) else err=abs(tmp-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if psi(i,j)=tmp end do end do end do end subroutine fix subroutine free(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 do j=2,ny-1 do i=2,nx-1 tmp=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) !-- 誤差の計算 --- if(psi(i,j)==0.0)then err=abs(tmp-psi(i,j))/abs(tmp) else err=abs(tmp-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if psi(i,j)=tmp end do end do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,2) psi(1,2:ny-1)=psi(2,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,ny-1) psi(nx,2:ny-1)=psi(nx-1,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,2)+psi(2,1)) psi(1,ny)=0.5*(psi(1,ny-1)+psi(2,ny)) psi(nx,1)=0.5*(psi(nx,2)+psi(nx-1,1)) psi(nx,ny)=0.5*(psi(nx,ny-1)+psi(nx-1,ny)) end do end subroutine free subroutine period(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 do j=2,ny-1 do i=2,nx-1 tmp=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) !-- 誤差の計算 --- if(psi(i,j)==0.0)then err=abs(tmp-psi(i,j))/abs(tmp) else err=abs(tmp-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if psi(i,j)=tmp end do end do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,ny-1) psi(1,2:ny-1)=psi(nx-1,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,2) psi(nx,2:ny-1)=psi(2,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,ny-1)+psi(nx-1,1)) psi(1,ny)=0.5*(psi(1,2)+psi(nx-1,ny)) psi(nx,1)=0.5*(psi(nx,ny-1)+psi(2,1)) psi(nx,ny)=0.5*(psi(nx,2)+psi(2,ny)) end do end subroutine period end subroutine Poisson_GauSei
Subroutine : | |||
nx : | integer, intent(in)
| ||
ny : | integer, intent(in)
| ||
dx : | real, intent(in)
| ||
dy : | real, intent(in)
| ||
rho(nx,ny) : | real, intent(in)
| ||
eps : | real, intent(in)
| ||
boundary : | integer, intent(in)
| ||
psi(nx,ny) : | real, intent(inout)
| ||
bound_opt(nx,ny) : | real, intent(in), optional
|
ヤコビ法によるポアソン方程式の求積(開発中openmp)
subroutine Poisson_Jacobi(nx, ny, dx, dy, rho, eps, boundary, psi, bound_opt) ! ヤコビ法によるポアソン方程式の求積(開発中openmp) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 integer, intent(in) :: boundary ! 境界条件 real, intent(in), optional :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: tmp, err, err_max ! boundary は 1 : 固定端境界, 2 : 自由端境界, 3 : 周期境界 ! rho =0 でラプラス方程式も求積可能. ! openmp によるスレッド並列が可能. ! ガウス・ザイデル法ではアルゴリズムの点から並列化が困難と思われたので, ! 並列計算によるポアソン方程式の求積が必要となるなら, ! ヤコビ法のものを使用されたい. psi = 0.0 select case (boundary) case(1) call fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) case(2) call free(nx,ny,dx,dy,eps,rho,psi) case(3) call period(nx,ny,dx,dy,eps,rho,psi) end select contains subroutine fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(in) :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 real :: tmp(nx,ny) ! ヤコビ法で解くために, イテレート後の値をプールする配列 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy !-- 固定端の設定 --- psi(1,:)=bound_opt(1,:) psi(nx,:)=bound_opt(nx,:) psi(:,1)=bound_opt(:,1) psi(:,nx)=bound_opt(:,nx) err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 tmp(i,j)=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) end do end do !$omp end parallel do !-- 誤差の計算 --- do j=2,ny-1 do i=2,nx-1 if(psi(i,j)==0.0)then err=abs(tmp(i,j)-psi(i,j))/abs(tmp(i,j)) else err=abs(tmp(i,j)-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if end do end do !$omp parallel do shared(tmp,psi) private(i,j) do j=2,ny-1 do i=2,nx-1 psi(i,j)=tmp(i,j) end do end do !$omp end parallel do end do end subroutine fix subroutine free(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 real :: tmp(nx,ny) ! ヤコビ法で解くために, イテレート後の値をプールする配列 integer :: i, j, k, l, m, n real :: delta delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 tmp(i,j)=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) end do end do !$omp end parallel do !-- 誤差の計算 --- do j=2,ny-1 do i=2,nx-1 if(psi(i,j)==0.0)then err=abs(tmp(i,j)-psi(i,j))/abs(tmp(i,j)) else err=abs(tmp(i,j)-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if end do end do !$omp parallel do shared(tmp,psi) private(i,j) do j=2,ny-1 do i=2,nx-1 psi(i,j)=tmp(i,j) end do end do !$omp end parallel do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,2) psi(1,2:ny-1)=psi(2,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,ny-1) psi(nx,2:ny-1)=psi(nx-1,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,2)+psi(2,1)) psi(1,ny)=0.5*(psi(1,ny-1)+psi(2,ny)) psi(nx,1)=0.5*(psi(nx,2)+psi(nx-1,1)) psi(nx,ny)=0.5*(psi(nx,ny-1)+psi(nx-1,ny)) end do end subroutine free subroutine period(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 real :: tmp(nx,ny) ! ヤコビ法で解くために, イテレート後の値をプールする配列 integer :: i, j, k, l, m, n real :: delta delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 tmp(i,j)=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) end do end do !$omp end parallel do !-- 誤差の計算 --- do j=2,ny-1 do i=2,nx-1 if(psi(i,j)==0.0)then err=abs(tmp(i,j)-psi(i,j))/abs(tmp(i,j)) else err=abs(tmp(i,j)-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if end do end do !$omp parallel do shared(tmp,psi,rho,delta,dx) private(i,j) do j=2,ny-1 do i=2,nx-1 psi(i,j)=tmp(i,j) end do end do !$omp end parallel do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,ny-1) psi(1,2:ny-1)=psi(nx-1,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,2) psi(nx,2:ny-1)=psi(2,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,ny-1)+psi(nx-1,1)) psi(1,ny)=0.5*(psi(1,2)+psi(nx-1,ny)) psi(nx,1)=0.5*(psi(nx,ny-1)+psi(2,1)) psi(nx,ny)=0.5*(psi(nx,2)+psi(2,ny)) end do end subroutine period end subroutine Poisson_Jacobi
Subroutine : | |||
nx : | integer, intent(in)
| ||
ny : | integer, intent(in)
| ||
dx : | real, intent(in)
| ||
dy : | real, intent(in)
| ||
rho(nx,ny) : | real, intent(in)
| ||
eps : | real, intent(in)
| ||
boundary : | integer, intent(in)
| ||
psi(nx,ny) : | real, intent(inout)
| ||
bound_opt(nx,ny) : | real, intent(in), optional
|
— ガウス=ザイデル法によるポアソン方程式の求積 — — 開発中!!!
subroutine diffus_Gausei(nx, ny, dx, dy, rho, eps, boundary, psi, bound_opt) !-- ガウス=ザイデル法によるポアソン方程式の求積 --- !-- 開発中!!! implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 integer, intent(in) :: boundary ! 境界条件 real, intent(in), optional :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: tmp, err, err_max ! boundary は 1 : 固定端境界, 2 : 自由端境界, 3 : 周期境界 ! rho =0 でラプラス方程式も求積可能 psi = 0.0 select case (boundary) case(1) call fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) case(2) call free(nx,ny,dx,dy,eps,rho,psi) case(3) call period(nx,ny,dx,dy,eps,rho,psi) end select contains subroutine fix(nx,ny,dx,dy,eps,rho,psi,bound_opt) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(in) :: bound_opt(nx,ny) ! 固定端境界の場合の境界値 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy !-- 固定端の設定 --- psi(1,:)=bound_opt(1,:) psi(nx,:)=bound_opt(nx,:) psi(:,1)=bound_opt(:,1) psi(:,nx)=bound_opt(:,nx) err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 do j=2,ny-1 do i=2,nx-1 tmp=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) !-- 誤差の計算 --- if(psi(i,j)==0.0)then err=abs(tmp-psi(i,j))/abs(tmp) else err=abs(tmp-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if psi(i,j)=tmp end do end do end do end subroutine fix subroutine free(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 do j=2,ny-1 do i=2,nx-1 tmp=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) !-- 誤差の計算 --- if(psi(i,j)==0.0)then err=abs(tmp-psi(i,j))/abs(tmp) else err=abs(tmp-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if psi(i,j)=tmp end do end do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,2) psi(1,2:ny-1)=psi(2,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,ny-1) psi(nx,2:ny-1)=psi(nx-1,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,2)+psi(2,1)) psi(1,ny)=0.5*(psi(1,ny-1)+psi(2,ny)) psi(nx,1)=0.5*(psi(nx,2)+psi(nx-1,1)) psi(nx,ny)=0.5*(psi(nx,ny-1)+psi(nx-1,ny)) end do end subroutine free subroutine period(nx,ny,dx,dy,eps,rho,psi) implicit none integer, intent(in) :: nx ! x 方向の配列要素 integer, intent(in) :: ny ! y 方向の配列要素 real, intent(in) :: dx ! x 方向の格子間隔 real, intent(in) :: dy ! y 方向の格子間隔 real, intent(in) :: rho(nx,ny) ! ポアソン方程式の強制項 real, intent(in) :: eps ! 収束条件 real, intent(inout) :: psi(nx,ny) ! ポアソン方程式の解 integer :: i, j, k, l, m, n real :: delta, err_max, err delta=dx/dy err_max=eps ! while に入るための便宜的措置 !-- 実際のソルバ --- do while(err_max>=eps) err_max=0.0 do j=2,ny-1 do i=2,nx-1 tmp=(0.5/(1.0+delta**2))*(-dx**2*rho(i,j) +(psi(i+1,j)+psi(i-1,j)+delta**2*(psi(i,j+1)+psi(i,j-1)))) !-- 誤差の計算 --- if(psi(i,j)==0.0)then err=abs(tmp-psi(i,j))/abs(tmp) else err=abs(tmp-psi(i,j))/abs(psi(i,j)) end if !-- 最大誤差の更新 if(err_max<=err)then err_max=err end if psi(i,j)=tmp end do end do !-- 境界条件の設定 psi(2:nx-1,1)=psi(2:nx-1,ny-1) psi(1,2:ny-1)=psi(nx-1,2:ny-1) psi(2:nx-1,ny)=psi(2:nx-1,2) psi(nx,2:ny-1)=psi(2,2:ny-1) !-- 4 隅の条件の設定 psi(1,1)=0.5*(psi(1,ny-1)+psi(nx-1,1)) psi(1,ny)=0.5*(psi(1,2)+psi(nx-1,ny)) psi(nx,1)=0.5*(psi(nx,ny-1)+psi(2,1)) psi(nx,ny)=0.5*(psi(nx,2)+psi(2,ny)) end do end subroutine period end subroutine diffus_GauSei