【课后习题】

一、程序填空题

程序填空第1题
1、用OpenMP Fortran API并行化下面的程序:

! This program implements a simple molecular dynamics simulation,!
   using the velocity Verlet time integration scheme. The particles
!   interact with a central pair potential.
!
! Author:   Bill Magro, Kuck and Associates, Inc. (KAI), 1998
!
! Parallelism is implemented via OpenMP directives.
! THIS PROGRAM USES THE FORTRAN90 RANDOM_NUMBER FUNCTION AND ARRAY
!   SYNTAX
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      program md
      implicit none
      ! simulation parameters
      integer ndim       ! dimensionality of the physical space
      integer nparts     ! number of particles
      integer nsteps     ! number of time steps in the simulation
      parameter(ndim=3,nparts=500,nsteps=1000)
      real*8 mass        ! mass of the particles
      real*8 dt          ! time step
      real*8 box(ndim)   ! dimensions of the simulation box
      parameter(mass=1.0,dt=1.0e-4)
      ! simulation variables
      real*8 position(ndim,nparts)
      real*8 velocity(ndim,nparts)
      real*8 force(ndim,nparts)
      real*8 accel(ndim,nparts)
      real*8 potential, kinetic, E0
      integer i
      box(1:ndim) = 10.
      ! set initial positions, velocities, and accelerations
      call initialize(nparts,ndim,box,position,velocity,accel)
      print *,"initialize successful"
      ! compute the forces and energies
      call compute(nparts,ndim,box,position,velocity,mass,force,potential,kinetic)
      print *,"compute successful"
      E0 = potential + kinetic
      ! This is the main time stepping loop
      do i=1,nsteps
          call compute(nparts,ndim,box,position,velocity,mass,force,potential,kinetic)
          write(*,*) potential, kinetic,(potential + kinetic - E0)/E0
          call update(nparts,ndim,position,velocity,force,accel,mass,dt)
      enddo
      end
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Compute the forces and energies, given positions, masses,
! and velocities
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      subroutine compute(np,nd,box,pos,vel,mass,f,pot,kin)
      implicit none
      integer np
      integer nd
      real*8  box(nd)
      real*8  pos(nd,np)
      real*8  vel(nd,np)
      real*8  f(nd,np)
      real*8  mass
      real*8  pot
      real*8  kin
      real*8 dotr8
      external dotr8
      real*8 v, dv, x
      integer i, j, k
      real*8  rij(nd)
      real*8  d
      real*8  PI2
      parameter(PI2=3.14159265d0/2.0d0)
      ! statement function for the pair potential and its derivative
      ! This potential is a harmonic well which smoothly saturates to a
      ! maximum value at PI/2.
      v(x) = sin(min(x,PI2))**2.
      dv(x) = 2.*sin(min(x,PI2))*cos(min(x,PI2))
      pot = 0.0
      kin = 0.0
      ! The computation of forces and energies is fully parallel.
     
     
     
     
      do i=1,np
        ! compute potential energy and forces
        f(1:nd,i) = 0.0
        do j=1,np
             if (i .ne. j) then
               call dist(nd,box,pos(1,i),pos(1,j),rij,d)
               ! attribute half of the potential energy to particle 'j'
               pot = pot + 0.5*v(d)
               do k=1,nd
                 f(k,i) = f(k,i) - rij(k)*dv(d)/d
               enddo
             endif
        enddo
        ! compute kinetic energy
        kin = kin + dotr8(nd,vel(1,i),vel(1,i))
      enddo
     
      kin = kin*0.5*mass
      return
      end
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Initialize the positions, velocities, and accelerations.
! The Fortran90 random_number function is used to choose positions.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      subroutine initialize(np,nd,box,pos,vel,acc)
      implicit none
      integer np
      integer nd
      real*8  box(nd)
      real*8  pos(nd,np)
      real*8  vel(nd,np)
      real*8  acc(nd,np)
      integer i, j
      real*8 x
      do i=1,np
        do j=1,nd
          call random_number(x)
          pos(j,i) = box(j)*x
          vel(j,i) = 0.0
          acc(j,i) = 0.0
        enddo
      enddo
      return
      end
! Compute the displacement vector (and its norm) between two particles.
      subroutine dist(nd,box,r1,r2,dr,d)
      implicit none
      integer nd
      real*8 box(nd)
      real*8 r1(nd)
      real*8 r2(nd)
      real*8 dr(nd)
      real*8 d
      integer i
      d = 0.0
      do i=1,nd
        dr(i) = r1(i) - r2(i)
        d = d + dr(i)**2.
      enddo
      d = sqrt(d)
      return
      end
! Return the dot product between two vectors of type real*8 and length n
      real*8 function dotr8(n,x,y)
      implicit none
      integer n
      real*8 x(n)
      real*8 y(n)
      integer i
      dotr8 = 0.0
      do i = 1,n
        dotr8 = dotr8 + x(i)*y(i)
      enddo
      return
      end
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Perform the time integration, using a velocity Verlet algorithm
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      subroutine update(np,nd,pos,vel,f,a,mass,dt)
      implicit none
      integer np
      integer nd
      real*8  pos(nd,np)
      real*8  vel(nd,np)
      real*8  f(nd,np)
      real*8  a(nd,np)
      real*8  mass
      real*8  dt
      integer i, j
      real*8  rmass
      rmass = 1.0/mass
      ! The time integration is fully parallel
     
     
     
      do i = 1,np
        do j = 1,nd
          pos(j,i) = pos(j,i) + vel(j,i)*dt + 0.5*dt*dt*a(j,i)
          vel(j,i) = vel(j,i) + 0.5*dt*(f(j,i)*rmass + a(j,i))
          a(j,i) = f(j,i)*rmass
        enddo
      enddo
     
      return
      end

2、用OpenMP Fortran API 并行化下面的程序。

      program main
************************************************************
* program to solve a finite difference
* discretization of Helmholtz equation : 
* (d2/dx2)u + (d2/dy2)u - alpha u = f
* using Jacobi iterative method.
*
* Modified: Sanjiv Shah,       Kuck and Associates, Inc. (KAI), 1998
* Author:   Joseph Robicheaux, Kuck and Associates, Inc. (KAI), 1998
*
* Directives are used in this code to achieve paralleism.
* All do loops are parallized with default 'static' scheduling.
*
* Input :  n - grid dimension in x direction
*          m - grid dimension in y direction
*          alpha - Helmholtz constant (always greater than 0.0)
*          tol   - error tolerance for iterative solver
*          relax - Successice over relaxation parameter
*          mits  - Maximum iterations for iterative solver
*
* On output
*       : u(n,m) - Dependent variable (solutions)
*       : f(n,m) - Right hand side function
*************************************************************
      implicit none
      integer n,m,mits
      double precision tol,relax,alpha
      common /idat/ n,m,mits
      common /fdat/tol,alpha,relax
*
* Read info
*
      write(*,*) "Input n,m - grid dimension in x,y direction "
      read(5,*) n,m
      write(*,*) "Input alpha - Helmholts constant "
      read(5,*) alpha
      write(*,*) "Input relax - Successive over-relaxation parameter"
      read(5,*) relax
      write(*,*) "Input tol - error tolerance for iterative solver"
      read(5,*) tol
      write(*,*) "Input mits - Maximum iterations for solver"
      read(5,*) mits
*
* Calls a driver routine
*
      call driver ()
      stop
      end
      subroutine driver ( )
*************************************************************
* Subroutine driver ()
* This is where the arrays are allocated and initialzed.
*
* Working varaibles/arrays
*     dx  - grid spacing in x direction
*     dy  - grid spacing in y direction
*************************************************************
      implicit none
      integer n,m,mits,mtemp
      double precision tol,relax,alpha
      common /idat/ n,m,mits,mtemp
      common /fdat/tol,alpha,relax
      double precision u(n,m),f(n,m),dx,dy
* Initialize data
      call initialize (n,m,alpha,dx,dy,u,f)
* Solve Helmholtz equation
      call jacobi (n,m,dx,dy,alpha,relax,u,f,tol,mits)
* Check error between exact solution
      call  error_check (n,m,alpha,dx,dy,u,f)
      return
      end
      subroutine initialize (n,m,alpha,dx,dy,u,f)
******************************************************
* Initializes data
* Assumes exact solution is u(x,y) = (1-x^2)*(1-y^2)
*
******************************************************
      implicit none
      integer n,m
      double precision u(n,m),f(n,m),dx,dy,alpha
      integer i,j, xx,yy
      double precision PI
      parameter (PI=3.1415926)
      dx = 2.0 / (n-1)
      dy = 2.0 / (m-1)
* Initilize initial condition and RHS
     
      do j = 1,m
         do i = 1,n
            xx = -1.0 + dx * dble(i-1)        ! -1 < x < 1
            yy = -1.0 + dy * dble(j-1)        ! -1 < y < 1
            u(i,j) = 0.0
            f(i,j) = -alpha *(1.0-xx*xx)*(1.0-yy*yy) - 2.0*(1.0-xx*xx)-2.0*(1.0-yy*yy)
         enddo
      enddo
     
      return
      end
      subroutine jacobi (n,m,dx,dy,alpha,omega,u,f,tol,maxit)
******************************************************************
* Subroutine HelmholtzJ
* Solves poisson equation on rectangular grid assuming :
* (1) Uniform discretization in each direction, and
* (2) Dirichlect boundary conditions
*
* Jacobi method is used in this routine
*
* Input : n,m   Number of grid points in the X/Y directions
*         dx,dy Grid spacing in the X/Y directions
*         alpha Helmholtz eqn. coefficient
*         omega Relaxation factor
*         f(n,m) Right hand side function
*         u(n,m) Dependent variable/Solution
*         tol    Tolerance for iterative solver
*         maxit  Maximum number of iterations
*
* Output : u(n,m) - Solution
*****************************************************************
      implicit none
      integer n,m,maxit
      double precision dx,dy,f(n,m),u(n,m),alpha, tol,omega
*
* Local variables
*
      integer i,j,k,k_local
      double precision error,resid,rsum,ax,ay,b
      double precision error_local, uold(n,m)
      real ta,tb,tc,td,te,ta1,ta2,tb1,tb2,tc1,tc2,td1,td2
      real te1,te2
      real second
      external second
*
* Initialize coefficients
      ax = 1.0/(dx*dx) ! X-direction coef
      ay = 1.0/(dy*dy) ! Y-direction coef
      b  = -2.0/(dx*dx)-2.0/(dy*dy) - alpha ! Central coeff 
      error = 10.0 * tol
      k = 1
      do while (k.le.maxit .and. error.gt. tol)
         error = 0.0   
* Copy new solution into old
     
     
         do j=1,m
            do i=1,n
               uold(i,j) = u(i,j)
            enddo
         enddo
* Compute stencil, residual, & update
     
         do j = 2,m-1
            do i = 2,n-1
*     Evaluate residual
               resid = (ax*(uold(i-1,j) + uold(i+1,j))& +  ay*(uold(i,j-1) + uold(i,j+1))& + b * uold(i,j) - f(i,j))/b
* Update solution
               u(i,j) = uold(i,j) - omega * resid
* Accumulate residual error
               error = error + resid*resid
            end do
         enddo
     
     
* Error check
         k = k + 1
         error = sqrt(error)/dble(n*m)
*
      enddo                     ! End iteration loop
*
      print *, 'Total Number of Iterations ', k
      print *, 'Residual                   ', error
      return
      end
      subroutine error_check (n,m,alpha,dx,dy,u,f)
      implicit none
************************************************************
* Checks error between numerical and exact solution
*
************************************************************
      integer n,m
      double precision u(n,m),f(n,m),dx,dy,alpha
      integer i,j
      double precision xx,yy,temp,error
      dx = 2.0 / (n-1)
      dy = 2.0 / (m-1)
      error = 0.0
     
      do j = 1,m
         do i = 1,n
            xx = -1.0d0 + dx * dble(i-1)
            yy = -1.0d0 + dy * dble(j-1)
            temp  = u(i,j) - (1.0-xx*xx)*(1.0-yy*yy)
            error = error + temp*temp
         enddo
      enddo
      error = sqrt(error)/dble(n*m)
      print *, 'Solution Error : ',error
      return

      end