program pirng

  ! Compute pi by counting the number of randomly generated point lying
  ! in a circle.  See Gropp et al., ``Using MPI'', Section 3.7.

  use rng
  implicit none

  ! MPI declarations
  include 'mpif.h'
  integer :: id, ierr, numprocs
  integer, parameter :: wp=selected_real_kind(12)

  integer, dimension(rng_s) :: seed
  type(rng_state) :: state

  ! A place to store random numbers
  integer, parameter :: m=1000
  real(wp), dimension(m) :: z

  ! Other local variables
  real(wp) ::  pi,t0
  integer :: iterations,a,sum,tot,i,j

  ! Set iteration count (each iteration computes m/2 points)
  iterations = 100000

  ! Initialize MPI
  call mpi_init(ierr)
  call mpi_comm_rank(mpi_comm_world, id, ierr)
  call mpi_comm_size(mpi_comm_world, numprocs, ierr)

  ! Determine and print the seed
  if (id == 0) then
     t0=mpi_wtime()
     call rng_set_seed(seed)
     print *,'An inefficient way to compute pi via Monte Carlo'
     print *,'Seed is set to ',rng_print_seed(seed)
  end if

  ! Tell everyone the value of seed
  call mpi_bcast(seed,rng_s,mpi_integer,0,mpi_comm_world,ierr)

  ! Advance the seed according to the MPI process number
  call rng_step_seed(seed,id)

  ! Initialize the random number generator
  call rng_init(seed,state)
      
  ! Determine the number of points inside a circle of radius 1
  a=0
  do i=(iterations*id)/numprocs,(iterations*(id+1))/numprocs-1
     call rng_number(state,z)
     do j=1,m,2
        if (z(j)**2 + z(j+1)**2 < 1.0_wp) then
           a=a+1
        end if
     end do
  end do

  ! Assemble the results onto process 0
  call mpi_reduce(a,sum,1,mpi_integer,mpi_sum,0,mpi_comm_world,ierr)

  ! Node 0 prints the answer.
  tot=iterations*m/2
  if (id == 0) then
     pi=(4.0_wp*sum)/tot
     print *, 'pi is approximately ',pi
     print *, 'wall time (s) =', mpi_wtime()-t0
  endif

  ! Terminate MPI
  call mpi_finalize(ierr)

  stop
end program pirng
