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