program impl !---------------------------------------------------

advertisement
program impl
!---------------------------------------------------implicit none
real(8),allocatable :: phi_new(:,:)
real(8),allocatable :: phi_old(:,:)
real(8)
:: dt,dx,dy,alfa,pi,kx,ky,kk
real(8)
:: gm, e, f
real(8)
:: t,x,y
real(8)
:: tmax,xmax,ymax
integer
:: i,j,n,nt,nx,ny,iw1
!==== for implicit analysis ==========================
real(8),allocatable :: sysmat(:,:)
real(8),allocatable :: eta(:),rhs(:)
integer,allocatable :: iphi2eta(:,:),ieta2phi(:,:)
integer
:: neqn,ieqn
!===== working space for conjugate gradient method ===
real(8),allocatable :: cgr(:),cgp(:),cgz(:),cgw(:),diag(:)
!------------------------------------------------------tmax=1.00001d0; xmax=1.00001d0; ymax=1.00001d0
WRITE(*,*) 'input time increment'
READ(*,*) dt
dx=0.025d0
dy=0.025d0
alfa=0.5d0
! setup for the coeficients -----kx=alfa*dt/(dx**2.d0) ! Dx in PPT
ky=alfa*dt/(dy**2.d0) ! Dy in PPT
gm=1.d0/(1.d0+2.d0*kx+2.d0*ky)
e=-1.d0*gm*kx; f=-1.d0*gm*ky
nt=int(tmax/dt)
nx=int(xmax/dx)+1
ny=int(ymax/dy)+1
neqn=(nx-2)*(ny-2)
! dymamic memory allocation for changeable arrays
allocate( phi_new(nx,ny),phi_old(nx,ny) )
allocate( sysmat( neqn, neqn ), eta( neqn ) ,rhs(neqn) )
allocate( cgr(neqn),cgp(neqn),cgz(neqn),cgw(neqn),diag(neqn) )
allocate( iphi2eta(nx,ny) , ieta2phi(2,neqn) )
! initialization for allocated arrays +++++++++++++++++++++++++++
phi_old(1:nx,1:ny)=0.d0
phi_new(1:nx,1:ny)=0.d0
! ======= for implicit analysis ===============
sysmat(1:neqn,1:neqn)=0.d0
eta(1:neqn)=0.d0; rhs(1:neqn)=0.d0
iphi2eta(1:nx,1:ny)=0
! ======= for conjugate gradient method =======
cgr(1:neqn)=0.d0; cgp(1:neqn)=0.d0
cgz(1:neqn)=0.d0; cgw(1:neqn)=0.d0
diag(1:neqn)=0.d0
! end initialization for allocated arrays ++++++++++++++++++++++++
! calculation of pi=3.14
pi=datan(1.d0)*4.d0
! overwrite with a fixed value on the boundary pointsyy
do j=1,ny
phi_old(1,j)= 0.d0
phi_old(nx,j)= 0.d0
enddo
do i=1,nx
phi_old(i,1)= dsin(pi*dble(i-1) * dx )
phi_old(i,ny)= 0.d0
enddo
! end overwrite with a fixed value on the boundary pointsyy
! ======= for implicit analysis ===============
ieqn=0
do j=2,ny-1
do i=2,nx-1
ieqn=ieqn+1
iphi2eta(i,j)=ieqn !-> input x,y cordinate, then output number of eqn.
ieta2phi(1,ieqn)=i !-> input number of eqn, then output x-cordinate
ieta2phi(2,ieqn)=j !-> input number of eqn, then output y-cordinate
enddo
enddo
! ==============================================
! ======= for implicit analysis ===============
! set system matrix of linear eqn. Don't calculate again during iterations
CALL set_SYSMAT(neqn,nx,ny,iphi2eta,ieta2phi,f,e,gm,sysmat)
! ==============================================
do n=1,nt
! ======= for implicit analysis =============== <= major change from explicit
version
! set right hand side vector of linear eqn.
CALL set_RHS(neqn,nx,ny,iphi2eta, ieta2phi,e, gm, phi_new, phi_old, rhs)
! solve linear eqn by conjugate gradient method
CALL slv_by_CG(n,neqn,sysmat,eta,rhs,cgr,cgp,cgz,cgw,diag)
do j=2,ny-1
do i=2,nx-1
phi_new(i,j)=eta( iphi2eta(i,j) )
enddo
enddo
! ============================================== <= end of major change
from explicit version
! overwrite with a fixed value on the boundary pointsyy
do j=1,ny
phi_new(1,j)= 0.d0
phi_new(nx,j)= 0.d0
enddo
do i=1,nx
phi_new(i,1)= dsin(pi*dble(i-1) * dx )
phi_new(i,ny)= 0.d0
enddo
! end overwrite with a fixed value on the boundary pointsyy
phi_old=phi_new
write(*,*) dt*n,phi_new(21,21)
! print results at specified steps
CALL output(n,nx,ny,dt,phi_new)
enddo
stop
end program impl
subroutine output(n,nx,ny,dt,phi_new)
implicit none
!----------------------------------------------------------------integer :: n, nx, ny,i,j
real(8) :: dt
real(8) :: phi_new(nx,ny)
!----------------------------------------------------------------if( ( dt*dble(n) - 0.1d0) .lt. 1d-6)then
open(11,file='print_at01.dat',status='replace')
do i=1,nx
write(11,'(41(1PE12.2))') (phi_new(i,j),j=1,ny)
enddo
close(11)
elseif( ( dt*dble(n) - 0.2d0) .lt. 1d-6)then
open(22,file='print_at02.dat',status='replace')
do i=1,nx
write(22,'(41(1PE12.2))') (phi_new(i,j),j=1,ny)
enddo
close(22)
elseif( ( dt*dble(n) - 0.5d0) .lt. 1d-6)then
open(33,file='print_at05.dat',status='replace')
do i=1,nx
write(33,'(41(1PE12.2))') (phi_new(i,j),j=1,ny)
enddo
close(33)
elseif( ( dt*dble(n) - 1.0d0) .lt. 1d-6)then
open(55,file='print_at10.dat',status='replace')
do i=1,nx
write(55,'(41(1PE12.2))') (phi_new(i,j),j=1,ny)
enddo
close(55)
end if
return
end subroutine output
!
++++++
Don't
see
this
below
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++
! ++++++ if you are interested in the solver 'conjugate gradient method', please see this
below +++
!
++++++
Don't
see
this
below
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++
subroutine slv_by_cg(it, neq, amat,
cgr,
cgp,
cgz,
x,
cgw,
b, &
Diag)
implicit none
!-----dimension for CGM array---------------------------integer :: i,istep,neq,it
real(8) :: amat(neq,neq)
real(8) :: x(neq),b(neq)
!
real(8) :: cgr(neq),cgp(neq),cgz(neq),cgw(neq)
real(8) :: Diag(neq)
real(8) :: arfa, beta, eita, cita, arfaold, betaold
real(8) :: err0, err, resid, zeroebe, bnorm, bcgw
!========= variables in this subroutine =======================
!
system_matrix {amat}
!
right side vector {b} , solution vector {x}
!
residual {r} vector --> {cgr}
!
predictor{p} vector --> {cgp}
!
{z} vector --> {cgz}
!
work
vector --> {cgw}
!
alfa or alfaold
!
beta or betaold
!===============================================================
!============
Precondition
===========================
CALL calc_precon(neq,amat,Diag)
!
!============
!-----------!
step1 <initiarize variables>
for CGM_EBE ----------------------
[K] * {x}
=> {cgw}
CALL matvec(neq,amat,x,cgw)
err0 = 0.d0
bnorm = 0.d0
bcgw = 0.d0
do i=1,neq
cgr(i) = b(i)-cgw(i)
err0 =err0 + cgr(i)**2
bnorm= bnorm+b(i)**2
bcgw= bcgw+cgw(i)**2
end do
err0=dsqrt(err0)
err=1.d0
!
1/diagK * {cgr} => {cgz}
do i=1,neq
cgz(i)=cgr(i)/Diag(i)
end do
================
do i=1,neq
cgp(i)=cgz(i)
end do
betaold=0.d0
arfaold=1.d0
!-------------------------------------------------------
!================= step2 <iterative step> ================
do istep=1,neq
WRITE(*,'(2i5,e12.5)') it,istep,err
!
!
<< step2-1 (solution of predictor_subspace) >>
[K] * {cgp}
=> {cgw}
CALL matvec(neq,amat,cgp,cgw)
eita=0.d0
cita=0.d0
do i=1,neq
eita=eita + cgr(i)*cgz(i)
cita=cita + cgp(i)*cgw(i)
end do
arfa=eita/cita
!
<< step2-2 (update solution) >>
do i=1,neq
x(i) = x(i) + arfa*cgp(i)
end do
!
<< step2-3 (calculata residual) >>
err=0.d0
do i=1,neq
cgr(i) = cgr(i) - arfa*cgw(i)
err
= err + cgr(i)**2
end do
err=dsqrt(err)
resid=err/err0
!
<< step2-4 (check the convergence) >>
zeroebe = 1.d-6
if( err .lt. zeroebe ) then
goto 9000
endif
!
!
<< step2-5 (update predictor direction) >>
[B}-1 * {workv1} => {workv3}
do i=1,neq
cgz(i)=cgr(i)/Diag(i)
end do
beta = 0.d0
do i=1,neq
beta = beta + cgr(i)*cgz(i)
end do
beta = beta / eita
do i=1,neq
cgp(i) = cgz(i) + beta*cgp(i)
end do
end do
write(*,*) '!!!!!!!!!! warnning !!!!!!!!!!!!!!!'
write(*,*) '-- number of iterations is "neq" ----'
write(*,*) '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
write(*,*) '
err ', err
9000 continue
return
end subroutine slv_by_cg
subroutine matvec(neq,amat,y1,y2)
implicit none
real(8) :: amat(neq,neq)
real(8) :: y1(neq),y2(neq)
integer :: i,j,neq
do i=1,neq
y2(i) = 0.d0
do j=1,neq
y2(i) = y2(i) + amat(i,j)*y1(j)
enddo
enddo
return
end subroutine matvec
subroutine calc_precon(neq,amat,diag)
implicit none
integer :: i,neq
real(8) :: amat(neq,neq)
real(8) :: diag(neq)
do i=1,neq
diag(i)=amat(i,i)
enddo
return
end subroutine calc_precon
subroutine set_SYSMAT(neq, nx, ny, iphi2eta, ieta2phi, f, e, gm, sysmat)
implicit none
!-----dimension for CGM array---------------------------integer :: neq, nx, ny
integer :: iphi2eta(nx,ny), ieta2phi(2,neq)
integer :: ieqn,ix, iy, ixm1, ixp1, iym1, iyp1, jeqn
real(8) :: sysmat(neq,neq)
real(8) :: f, e, gm
!
return
end subroutine set_SYSMAT
subroutine set_RHS(neq, nx, ny, iphi2eta, ieta2phi, e, gm, phi, phi_old, rhs)
implicit none
!-----dimension for CGM array---------------------------integer :: neq, nx, ny, ix, iy, ieqn
integer :: iphi2eta(nx,ny), ieta2phi(2,neq)
real(8) :: rhs(neq), phi(nx,ny), phi_old(nx,ny)
real(8) :: e, gm
!
return
end subroutine set_RHS
Download