Class Alge_Solv
In: alge_solv.f90

代数演算を用いて偏微分方程式を解くモジュール

Methods

Public Instance methods

Subroutine :
nx :integer, intent(in)
: x 方向の配列要素
ny :integer, intent(in)
: y 方向の配列要素
dx :real, intent(in)
: x 方向の格子間隔
dy :real, intent(in)
: y 方向の格子間隔
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)

[Source]

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)
: x 方向の配列要素
ny :integer, intent(in)
: y 方向の配列要素
dx :real, intent(in)
: x 方向の格子間隔
dy :real, intent(in)
: y 方向の格子間隔
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
: 固定端境界の場合の境界値

— ガウス=ザイデル法によるポアソン方程式の求積 —

[Source]

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)
: x 方向の配列要素
ny :integer, intent(in)
: y 方向の配列要素
dx :real, intent(in)
: x 方向の格子間隔
dy :real, intent(in)
: y 方向の格子間隔
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)

[Source]

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)
: x 方向の配列要素
ny :integer, intent(in)
: y 方向の配列要素
dx :real, intent(in)
: x 方向の格子間隔
dy :real, intent(in)
: y 方向の格子間隔
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
: 固定端境界の場合の境界値

— ガウス=ザイデル法によるポアソン方程式の求積 — — 開発中!!!

[Source]

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