next up previous
Next: Code explanation Up: Problem 2 Previous: Problem 2.2b

Code : LAPLACE

       program laplace

       interface
          subroutine initial_u(u,nx,ny)
             integer nx,ny
             double precision, dimension (1:nx,1:ny) :: u
          end subroutine

          subroutine get_coordinates(xcoord,ycoord,nx,ny)
             integer nx,ny
             double precision, dimension(1:nx) :: xcoord
             double precision, dimension(1:ny) :: ycoord
          end subroutine

       subroutine put_boundary_value(u,nx,ny,xcoord,ycoord)
          double precision, dimension(1:nx,1:ny) :: u
          integer nx,ny
          double precision, dimension(1:nx) :: xcoord
          double precision, dimension(1:ny) :: ycoord
       end subroutine

       subroutine jacobi(u,uold,nx,ny)
          integer nx,ny
          double precision, dimension(1:nx,1:ny) :: u,uold
       end subroutine

       subroutine anal_error(error,u,nx,ny,xcoord,ycoord)
          double precision error
          integer nx,ny
          double precision, dimension(1:nx, 1:ny):: u
          double precision, dimension(1:nx) :: xcoord
          double precision, dimension(1:ny) :: ycoord
       end subroutine

       subroutine interior_avg(u,nx,ny)
          integer nx,ny
          double precision, dimension(1:nx,1:ny)  :: u
       end subroutine
       end interface

       parameter(nx = 21)
       parameter(ny = 11)
       integer i,count
       double precision error
       double precision, dimension(1:nx, 1:ny):: u,uold
       double precision, dimension(1:nx) :: xcoord
       double precision, dimension(1:ny) :: ycoord

       write(*,*) 'MESH RESOLUTION INFO:'
       write(*,*) 'dx is ',2.0d0/dble(nx-1)
       write(*,*) 'dy is ',1.0d0/dble(ny-1)

       ! GET COORDINATES
       call get_coordinates(xcoord,ycoord,nx,ny)

       ! SET U to 0, UOLD to 1.0
       u = 0.0d0
       uold = 1.0d0
       count = 0

       ! PUT BOUNDARY VALUES ON THE BOUNDARIES
       call put_boundary_value(u,nx,ny,xcoord,ycoord)

       call interior_avg(u,nx,ny)

       error = 1.0d0
       do while( error > 3.0d-06 )
          count = count + 1
          call jacobi(u,uold,nx,ny)
          error = maxval(abs(u-uold)) 
!         write(*,*) 'infinity norm between u and uold after step ', &
!                    count,' is ',error
       enddo

       write(*,*) 'PROGRAM COMPLETE!'
       write(*,*) 'total number of Jacobi iteration steps: ',count
       write(*,*) '   '
       write(*,*) 'infinity norm between u and uold for last ', &
                  'Jacobi step is',error
       call anal_error(error,u,nx,ny,xcoord,ycoord)
       write(*,*) '   '
       write(*,*) 'infinity norm between u and the analytical ', &
                  'solution is ',error
       end

!********************************************************************
!** INTERIOR_AVG
!********************************************************************
!*** This routine calculates the average of the boundary of the 
!*** input grid u, and sets the interior points of the grid
!*** to that value
!********************************************************************
       subroutine interior_avg(u,nx,ny)
          integer nx,ny
          double precision, dimension(1:nx,1:ny)  :: u
          ! local var
          double precision avg

       avg = 0.0d0
       do i=1,nx
          avg = avg + u(i,1) + u(i,ny)
       enddo
       do i=1,ny
          avg = avg + u(1,i) + u(nx,i)
       enddo
       avg = avg / dble(2 * (nx + ny))
       do i=2,nx-1
       do j=2,ny-1
          u(i,j) = avg
       enddo
       enddo

       end
          

!********************************************************************
!*** ANAL_ERROR
!********************************************************************
!*** This routine returns the infinity norm between the input
!*** grid u and the known analytic solution (sampled at the grid points)
!********************************************************************
       subroutine anal_error(error,u,nx,ny,xcoord,ycoord)
          double precision error
          integer nx,ny
          double precision, dimension(1:nx, 1:ny):: u
          double precision, dimension(1:nx) :: xcoord
          double precision, dimension(1:ny) :: ycoord
          ! local variables
          double precision, dimension(1:nx,1:ny) :: utemp

       do i=1,nx
       do j=1,ny
          call calc_u(utemp(i,j),xcoord(i),ycoord(j))
       enddo
       enddo
       error = maxval(abs(u-utemp))

       end







!********************************************************************
!*** JACOBI
!********************************************************************
!*** This routine performs one jacobi iteration on the 
!*** input grid u.  The new values are returned in u, and 
!*** uold on output contains the input u.
!********************************************************************
       subroutine jacobi(u,uold,nx,ny)
          integer nx,ny
          double precision, dimension(1:nx,1:ny) :: u,uold

       uold = u
       do i=2,nx-1
       do j=2,ny-1
          u(i,j) = (uold(i-1,j) + uold(i+1,j) + uold(i,j-1) + &
                    uold(i,j+1) )/4.0d0
       enddo
       enddo
       
       end
!********************************************************************
!*** PUT_BOUNDARY_VALUE
!********************************************************************
!*** This routine puts the boundary values on the boundary of u
!********************************************************************
       subroutine put_boundary_value(u,nx,ny,xcoord,ycoord)
          interface
             subroutine calc_u( uval,x,y)
                double precision uval,x,y
             end subroutine
          end interface

          double precision, dimension(1:nx,1:ny) :: u
          integer nx,ny
          double precision, dimension(1:nx) :: xcoord
          double precision, dimension(1:ny) :: ycoord

       do i=1,nx
          call calc_u( u(i,1) ,xcoord(i),0.0d0)
          call calc_u( u(i,ny), xcoord(i),1.0d0)
       enddo
       do i=1,ny
          call calc_u( u(1,i), 0.0d0, ycoord(i))
          call calc_u( u(nx,i), 2.0d0, ycoord(i))
       enddo

       end

!*******************************************************************
!*** CALC_U
!*******************************************************************
!*** This routine calculates an analytic function, and returns it
!*** in uval
!*******************************************************************

       subroutine calc_u( uval,x,y)
          double precision uval,x,y
       uval = -4.7 + 0.2 * x - 0.3 * y + 0.09 * (x * x - y * y)
       uval = uval + log(sqrt( ((x+0.2)**2.0) + ((y+0.2)**2.0) ) )
!      write(*,*) uval,x,y
       end subroutine




!********************************************************************
!*** GET_COORDINATES
!********************************************************************
!*** This routine calculates the coordinates for the X-Y mesh
!********************************************************************
       subroutine get_coordinates(xcoord,ycoord,nx,ny)
          integer nx,ny
          double precision, dimension(1:nx) :: xcoord
          double precision, dimension(1:ny) :: ycoord

       do i = 1,nx
          xcoord(i) = 2.0 * dble(i-1)/dble(nx-1)
       enddo
       do i = 1,ny
          ycoord(i) = 1.0 * (dble(i-1)/dble(ny-1))
       enddo
       
       end




!********************************************************************

       subroutine initial_u(u,nx,ny)
          integer nx,ny
          double precision, dimension(1:nx,1:ny) :: u

          u = 0.0

       end





Mark Miller
Wed Oct 11 16:43:42 EDT 1995