| 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